* Re: TCP event tracking via netlink...
From: Arnaldo Carvalho de Melo @ 2007-12-06 13:28 UTC (permalink / raw)
To: David Miller; +Cc: shemminger, joe, ilpo.jarvinen, netdev
In-Reply-To: <20071206.022058.153600766.davem@davemloft.net>
Em Thu, Dec 06, 2007 at 02:20:58AM -0800, David Miller escreveu:
> From: Stephen Hemminger <shemminger@linux-foundation.org>
> Date: Wed, 5 Dec 2007 16:33:38 -0500
>
> > On Wed, 05 Dec 2007 08:53:07 -0800
> > Joe Perches <joe@perches.com> wrote:
> >
> > > > it occurred to me that we might want to do something
> > > > like a state change event generator.
> > >
> > > This could be a basis for an interesting TCP
> > > performance tester.
> >
> > That is what tcpprobe does but it isn't detailed enough to address SACK
> > issues.
>
> Indeed, this could be done via the jprobe there.
>
> Silly me I didn't do this in the implementation I whipped
> up, which I'll likely correct.
I have some experiments from the past on this area:
This is what is produced by ctracer + the ostra callgrapher when
tracking many sk_buff objects, tracing sk_buff routines and as well all
other structs that have a pointer to a sk_buff, i.e. where the sk_buff
can be get from the struct that has a pointer to it, tcp_sock is an
"alias" to struct inet_sock that is an "alias" to struct sock, etc, so
when tracing tcp_sock you also trace inet_connection_sock, inet_sock,
sock methods:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sk_buff/many_objects/
With just one object (that is reused, so appears many times):
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sk_buff/0xffff8101013130e8/
Following struct sock methods:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sock/many_objects/
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sock/0xf61bf500/
struct socket:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/socket/many_objects/
It works by using the DWARF information to generate a systemtap module
that in turn will create a relayfs channel where we store the traces and
a automatically reorganized struct with just the base types (int, char,
long, etc) and typedefs that end up being base types.
Example of the struct minisock recreated from the debugging information
and reorganized using the algorithms in pahole to save space, generated
by this tool, go to the bottom, where you'll find struct
ctracer__mini_sock and the collector, that from a full sized object
creates the mini struct.
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/ctracer_collector.struct.sock.c
And the systemtap module (the tcpprobe on steroids) automatically
generated:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/ctracer_methods.struct.sock.stp
This requires more work to:
. reduce the overhead
. filter out undesired functions creating a "project" with the functions desired using
some gui editor
. specify lists of fields to put on the internal state to be collected, again using a
gui or plain ctracer-edit using vi, instead of getting just base types
. Be able to say: collect just the fields on the second and fourth cacheline
. collectors for complex objects such as spinlocks, socket lock, mutexes
But since people are wanting to work on tools to watch state
transitions, fields changing, etc, I thought I should dust off the ostra
experiments and the more recent dwarves ctracer work I'm doing on my
copious spare time 8)
In the callgrapher there are some more interesting stuff:
Interface to see where fields changed:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sock/0xf61bf500/changes.html
In this page clicking on a field name, such as:
http://oops.ghostprotocols.net:81/acme/dwarves/callgraphs/sock/0xf61bf500/sk_forward_alloc.png
You'll get graphs over time.
Code is in the dwarves repo at:
http://master.kernel.org/git/?p=linux/kernel/git/acme/pahole.git;a=summary
Thanks,
- Arnaldo
^ permalink raw reply
* [RFC2][PATCH 7/7] [TFRC]: New rx history code
From: Arnaldo Carvalho de Melo @ 2007-12-06 13:03 UTC (permalink / raw)
To: Gerrit Renker; +Cc: dccp, netdev
Gerrit,
I think I got this right this time, please see if there is
anything left so that we can move on. I plan to go thru the following
patches restricting myself to namespacing and consistency issues,
leaving ideas I have for later, when we get more of your backlog merged.
The first six patches in this series are unmodified, so if you
are OK with them please send me your Signed-off-by.
Thanks a lot,
- Arnaldo
>From 2a3b4067dd514ce0e307d165783bc561cc7f17c4 Mon Sep 17 00:00:00 2001
From: Arnaldo Carvalho de Melo <acme@redhat.com>
Date: Thu, 6 Dec 2007 10:56:58 -0200
Subject: [PATCH 7/7] [TFRC]: New rx history code
Credit here goes to Gerrit Renker, that provided the initial implementation for
this new codebase.
I modified it just to try to make it closer to the existing API, renaming some
functions, add namespacing and fix one bug where the tfrc_rx_hist_alloc was not
freeing the allocated ring entries on the error path.
Original changeset comment from Gerrit:
-----------
This provides a new, self-contained and generic RX history service for TFRC
based protocols.
Details:
* new data structure, initialisation and cleanup routines;
* allocation of dccp_rx_hist entries local to packet_history.c,
as a service exported by the dccp_tfrc_lib module.
* interface to automatically track highest-received seqno;
* receiver-based RTT estimation (needed for instance by RFC 3448, 6.3.1);
* a generic function to test for `data packets' as per RFC 4340, sec. 7.7.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
net/dccp/ccids/ccid3.c | 292 +++++++++++++----------------------
net/dccp/ccids/ccid3.h | 14 +-
net/dccp/ccids/lib/loss_interval.c | 13 ++-
net/dccp/ccids/lib/packet_history.c | 290 +++++++++++++++++++++--------------
net/dccp/ccids/lib/packet_history.h | 83 +++++------
5 files changed, 334 insertions(+), 358 deletions(-)
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c
index 5ff5aab..28a5e4d 100644
--- a/net/dccp/ccids/ccid3.c
+++ b/net/dccp/ccids/ccid3.c
@@ -641,6 +641,15 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
/*
* Receiver Half-Connection Routines
*/
+
+/* CCID3 feedback types */
+enum ccid3_fback_type {
+ CCID3_FBACK_NONE = 0,
+ CCID3_FBACK_INITIAL,
+ CCID3_FBACK_PERIODIC,
+ CCID3_FBACK_PARAM_CHANGE
+};
+
#ifdef CONFIG_IP_DCCP_CCID3_DEBUG
static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
{
@@ -667,59 +676,60 @@ static void ccid3_hc_rx_set_state(struct sock *sk,
hcrx->ccid3hcrx_state = state;
}
-static inline void ccid3_hc_rx_update_s(struct ccid3_hc_rx_sock *hcrx, int len)
-{
- if (likely(len > 0)) /* don't update on empty packets (e.g. ACKs) */
- hcrx->ccid3hcrx_s = tfrc_ewma(hcrx->ccid3hcrx_s, len, 9);
-}
-
-static void ccid3_hc_rx_send_feedback(struct sock *sk)
+static void ccid3_hc_rx_send_feedback(struct sock *sk,
+ const struct sk_buff *skb,
+ enum ccid3_fback_type fbtype)
{
struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- struct tfrc_rx_hist_entry *packet;
ktime_t now;
- suseconds_t delta;
+ s64 delta = 0;
ccid3_pr_debug("%s(%p) - entry \n", dccp_role(sk), sk);
+ if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_TERM))
+ return;
+
now = ktime_get_real();
- switch (hcrx->ccid3hcrx_state) {
- case TFRC_RSTATE_NO_DATA:
+ switch (fbtype) {
+ case CCID3_FBACK_INITIAL:
hcrx->ccid3hcrx_x_recv = 0;
+ hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */
break;
- case TFRC_RSTATE_DATA:
- delta = ktime_us_delta(now,
- hcrx->ccid3hcrx_tstamp_last_feedback);
- DCCP_BUG_ON(delta < 0);
- hcrx->ccid3hcrx_x_recv =
- scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
+ case CCID3_FBACK_PARAM_CHANGE:
+ /*
+ * When parameters change (new loss or p > p_prev), we do not
+ * have a reliable estimate for R_m of [RFC 3448, 6.2] and so
+ * need to reuse the previous value of X_recv. However, when
+ * X_recv was 0 (due to early loss), this would kill X down to
+ * s/t_mbi (i.e. one packet in 64 seconds).
+ * To avoid such drastic reduction, we approximate X_recv as
+ * the number of bytes since last feedback.
+ * This is a safe fallback, since X is bounded above by X_calc.
+ */
+ if (hcrx->ccid3hcrx_x_recv > 0)
+ break;
+ /* fall through */
+ case CCID3_FBACK_PERIODIC:
+ delta = ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_feedback);
+ if (delta <= 0)
+ DCCP_BUG("delta (%ld) <= 0", (long)delta);
+ else
+ hcrx->ccid3hcrx_x_recv =
+ scaled_div32(hcrx->ccid3hcrx_bytes_recv, delta);
break;
- case TFRC_RSTATE_TERM:
- DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
+ default:
return;
}
- packet = tfrc_rx_hist_find_data_packet(&hcrx->ccid3hcrx_hist);
- if (unlikely(packet == NULL)) {
- DCCP_WARN("%s(%p), no data packet in history!\n",
- dccp_role(sk), sk);
- return;
- }
+ ccid3_pr_debug("Interval %ldusec, X_recv=%u, 1/p=%u\n", (long)delta,
+ hcrx->ccid3hcrx_x_recv, hcrx->ccid3hcrx_pinv);
hcrx->ccid3hcrx_tstamp_last_feedback = now;
- hcrx->ccid3hcrx_ccval_last_counter = packet->tfrchrx_ccval;
+ hcrx->ccid3hcrx_last_counter = dccp_hdr(skb)->dccph_ccval;
hcrx->ccid3hcrx_bytes_recv = 0;
- if (hcrx->ccid3hcrx_p == 0)
- hcrx->ccid3hcrx_pinv = ~0U; /* see RFC 4342, 8.5 */
- else if (hcrx->ccid3hcrx_p > 1000000) {
- DCCP_WARN("p (%u) > 100%%\n", hcrx->ccid3hcrx_p);
- hcrx->ccid3hcrx_pinv = 1; /* use 100% in this case */
- } else
- hcrx->ccid3hcrx_pinv = 1000000 / hcrx->ccid3hcrx_p;
-
dp->dccps_hc_rx_insert_options = 1;
dccp_send_ack(sk);
}
@@ -750,165 +760,78 @@ static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
return 0;
}
-static int ccid3_hc_rx_detect_loss(struct sock *sk,
- struct tfrc_rx_hist_entry *packet)
-{
- struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- struct tfrc_rx_hist_entry *rx_hist =
- tfrc_rx_hist_head(&hcrx->ccid3hcrx_hist);
- u64 seqno = packet->tfrchrx_seqno;
- u64 tmp_seqno;
- int loss = 0;
- u8 ccval;
-
-
- tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
-
- if (!rx_hist ||
- follows48(packet->tfrchrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
- hcrx->ccid3hcrx_seqno_nonloss = seqno;
- hcrx->ccid3hcrx_ccval_nonloss = packet->tfrchrx_ccval;
- goto detect_out;
- }
-
-
- while (dccp_delta_seqno(hcrx->ccid3hcrx_seqno_nonloss, seqno)
- > TFRC_RECV_NUM_LATE_LOSS) {
- loss = 1;
- dccp_li_update_li(sk,
- &hcrx->ccid3hcrx_li_hist,
- &hcrx->ccid3hcrx_hist,
- hcrx->ccid3hcrx_tstamp_last_feedback,
- hcrx->ccid3hcrx_s,
- hcrx->ccid3hcrx_bytes_recv,
- hcrx->ccid3hcrx_x_recv,
- hcrx->ccid3hcrx_seqno_nonloss,
- hcrx->ccid3hcrx_ccval_nonloss);
- tmp_seqno = hcrx->ccid3hcrx_seqno_nonloss;
- dccp_inc_seqno(&tmp_seqno);
- hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
- dccp_inc_seqno(&tmp_seqno);
- while (tfrc_rx_hist_find_entry(&hcrx->ccid3hcrx_hist,
- tmp_seqno, &ccval)) {
- hcrx->ccid3hcrx_seqno_nonloss = tmp_seqno;
- hcrx->ccid3hcrx_ccval_nonloss = ccval;
- dccp_inc_seqno(&tmp_seqno);
- }
- }
-
- /* FIXME - this code could be simplified with above while */
- /* but works at moment */
- if (follows48(packet->tfrchrx_seqno, hcrx->ccid3hcrx_seqno_nonloss)) {
- hcrx->ccid3hcrx_seqno_nonloss = seqno;
- hcrx->ccid3hcrx_ccval_nonloss = packet->tfrchrx_ccval;
- }
-
-detect_out:
- tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist,
- &hcrx->ccid3hcrx_li_hist, packet,
- hcrx->ccid3hcrx_seqno_nonloss);
- return loss;
-}
-
static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
{
struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
- const struct dccp_options_received *opt_recv;
- struct tfrc_rx_hist_entry *packet;
- u32 p_prev, r_sample, rtt_prev;
- int loss, payload_size;
- ktime_t now;
-
- opt_recv = &dccp_sk(sk)->dccps_options_received;
-
- switch (DCCP_SKB_CB(skb)->dccpd_type) {
- case DCCP_PKT_ACK:
- if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
- return;
- case DCCP_PKT_DATAACK:
- if (opt_recv->dccpor_timestamp_echo == 0)
- break;
- r_sample = dccp_timestamp() - opt_recv->dccpor_timestamp_echo;
- rtt_prev = hcrx->ccid3hcrx_rtt;
- r_sample = dccp_sample_rtt(sk, 10 * r_sample);
-
- if (hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)
- hcrx->ccid3hcrx_rtt = r_sample;
- else
- hcrx->ccid3hcrx_rtt = (hcrx->ccid3hcrx_rtt * 9) / 10 +
- r_sample / 10;
-
- if (rtt_prev != hcrx->ccid3hcrx_rtt)
- ccid3_pr_debug("%s(%p), New RTT=%uus, elapsed time=%u\n",
- dccp_role(sk), sk, hcrx->ccid3hcrx_rtt,
- opt_recv->dccpor_elapsed_time);
- break;
- case DCCP_PKT_DATA:
- break;
- default: /* We're not interested in other packet types, move along */
- return;
- }
-
- packet = tfrc_rx_hist_entry_new(opt_recv->dccpor_ndp, skb, GFP_ATOMIC);
- if (unlikely(packet == NULL)) {
- DCCP_WARN("%s(%p), Not enough mem to add rx packet "
- "to history, consider it lost!\n", dccp_role(sk), sk);
- return;
- }
-
- loss = ccid3_hc_rx_detect_loss(sk, packet);
+ enum ccid3_fback_type do_feedback = CCID3_FBACK_NONE;
+ const u32 ndp = dccp_sk(sk)->dccps_options_received.dccpor_ndp;
+ const bool is_data_packet = dccp_data_packet(skb);
+
+ if (unlikely(hcrx->ccid3hcrx_state == TFRC_RSTATE_NO_DATA)) {
+ if (is_data_packet) {
+ const u32 payload = skb->len - dccp_hdr(skb)->dccph_doff * 4;
+ do_feedback = CCID3_FBACK_INITIAL;
+ ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
+ hcrx->ccid3hcrx_s = payload;
+ /*
+ * Updating ccid3hcrx_bytes_recv is in fact not needed
+ * here and if it would be done it would not have a
+ * useable effect. The reason is that the first data
+ * packet will trigger the initial feedback; and in the
+ * initial feedback packet X_recv (which is
+ * ccid3hcrx_bytes_recv / the_time_spent) is set to 0
+ * (RFC 3448, 6.3) - Gerrit
+ */
+ }
+ goto update_records;
+ }
- if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK)
- return;
+ if (tfrc_rx_hist_duplicate(&hcrx->ccid3hcrx_hist, skb))
+ return; /* done receiving */
- payload_size = skb->len - dccp_hdr(skb)->dccph_doff * 4;
- ccid3_hc_rx_update_s(hcrx, payload_size);
+ if (is_data_packet) {
+ const u32 payload = skb->len - dccp_hdr(skb)->dccph_doff * 4;
+ /*
+ * Update moving-average of s and the sum of received payload bytes
+ */
+ hcrx->ccid3hcrx_s = tfrc_ewma(hcrx->ccid3hcrx_s, payload, 9);
+ hcrx->ccid3hcrx_bytes_recv += payload;
+ }
- switch (hcrx->ccid3hcrx_state) {
- case TFRC_RSTATE_NO_DATA:
- ccid3_pr_debug("%s(%p, state=%s), skb=%p, sending initial "
- "feedback\n", dccp_role(sk), sk,
- dccp_state_name(sk->sk_state), skb);
- ccid3_hc_rx_send_feedback(sk);
- ccid3_hc_rx_set_state(sk, TFRC_RSTATE_DATA);
- return;
- case TFRC_RSTATE_DATA:
- hcrx->ccid3hcrx_bytes_recv += payload_size;
- if (loss)
- break;
+ /*
+ * Handle pending losses and otherwise check for new loss
+ */
+ if (tfrc_rx_hist_new_loss_indicated(&hcrx->ccid3hcrx_hist, skb, ndp))
+ goto update_records;
- now = ktime_get_real();
- if ((ktime_us_delta(now, hcrx->ccid3hcrx_tstamp_last_ack) -
- (s64)hcrx->ccid3hcrx_rtt) >= 0) {
- hcrx->ccid3hcrx_tstamp_last_ack = now;
- ccid3_hc_rx_send_feedback(sk);
- }
- return;
- case TFRC_RSTATE_TERM:
- DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
- return;
+ /*
+ * Handle data packets: RTT sampling and monitoring p
+ */
+ if (unlikely(!is_data_packet))
+ goto update_records;
+
+ if (list_empty(&hcrx->ccid3hcrx_li_hist)) { /* no loss so far: p = 0 */
+ const u32 sample = tfrc_rx_hist_sample_rtt(&hcrx->ccid3hcrx_hist, skb);
+ /*
+ * Empty loss history: no loss so far, hence p stays 0.
+ * Sample RTT values, since an RTT estimate is required for the
+ * computation of p when the first loss occurs; RFC 3448, 6.3.1.
+ */
+ if (sample != 0)
+ hcrx->ccid3hcrx_rtt = tfrc_ewma(hcrx->ccid3hcrx_rtt, sample, 9);
}
- /* Dealing with packet loss */
- ccid3_pr_debug("%s(%p, state=%s), data loss! Reacting...\n",
- dccp_role(sk), sk, dccp_state_name(sk->sk_state));
-
- p_prev = hcrx->ccid3hcrx_p;
-
- /* Calculate loss event rate */
- if (!list_empty(&hcrx->ccid3hcrx_li_hist)) {
- u32 i_mean = dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist);
+ /*
+ * Check if the periodic once-per-RTT feedback is due; RFC 4342, 10.3
+ */
+ if (SUB16(dccp_hdr(skb)->dccph_ccval, hcrx->ccid3hcrx_last_counter) > 3)
+ do_feedback = CCID3_FBACK_PERIODIC;
- /* Scaling up by 1000000 as fixed decimal */
- if (i_mean != 0)
- hcrx->ccid3hcrx_p = 1000000 / i_mean;
- } else
- DCCP_BUG("empty loss history");
+update_records:
+ tfrc_rx_hist_add_packet(&hcrx->ccid3hcrx_hist, skb, ndp);
- if (hcrx->ccid3hcrx_p > p_prev) {
- ccid3_hc_rx_send_feedback(sk);
- return;
- }
+ if (do_feedback)
+ ccid3_hc_rx_send_feedback(sk, skb, do_feedback);
}
static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
@@ -918,11 +841,8 @@ static int ccid3_hc_rx_init(struct ccid *ccid, struct sock *sk)
ccid3_pr_debug("entry\n");
hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA;
- INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist);
INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist);
- hcrx->ccid3hcrx_tstamp_last_feedback =
- hcrx->ccid3hcrx_tstamp_last_ack = ktime_get_real();
- return 0;
+ return tfrc_rx_hist_alloc(&hcrx->ccid3hcrx_hist);
}
static void ccid3_hc_rx_exit(struct sock *sk)
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h
index b842a7d..3c33dc6 100644
--- a/net/dccp/ccids/ccid3.h
+++ b/net/dccp/ccids/ccid3.h
@@ -1,7 +1,8 @@
/*
* net/dccp/ccids/ccid3.h
*
- * Copyright (c) 2005-6 The University of Waikato, Hamilton, New Zealand.
+ * Copyright (c) 2005-7 The University of Waikato, Hamilton, New Zealand.
+ * Copyright (c) 2007 The University of Aberdeen, Scotland, UK
*
* An implementation of the DCCP protocol
*
@@ -135,9 +136,7 @@ enum ccid3_hc_rx_states {
* @ccid3hcrx_x_recv - Receiver estimate of send rate (RFC 3448 4.3)
* @ccid3hcrx_rtt - Receiver estimate of rtt (non-standard)
* @ccid3hcrx_p - current loss event rate (RFC 3448 5.4)
- * @ccid3hcrx_seqno_nonloss - Last received non-loss sequence number
- * @ccid3hcrx_ccval_nonloss - Last received non-loss Window CCVal
- * @ccid3hcrx_ccval_last_counter - Tracks window counter (RFC 4342, 8.1)
+ * @ccid3hcrx_last_counter - Tracks window counter (RFC 4342, 8.1)
* @ccid3hcrx_state - receiver state, one of %ccid3_hc_rx_states
* @ccid3hcrx_bytes_recv - Total sum of DCCP payload bytes
* @ccid3hcrx_tstamp_last_feedback - Time at which last feedback was sent
@@ -152,14 +151,11 @@ struct ccid3_hc_rx_sock {
#define ccid3hcrx_x_recv ccid3hcrx_tfrc.tfrcrx_x_recv
#define ccid3hcrx_rtt ccid3hcrx_tfrc.tfrcrx_rtt
#define ccid3hcrx_p ccid3hcrx_tfrc.tfrcrx_p
- u64 ccid3hcrx_seqno_nonloss:48,
- ccid3hcrx_ccval_nonloss:4,
- ccid3hcrx_ccval_last_counter:4;
+ u8 ccid3hcrx_last_counter:4;
enum ccid3_hc_rx_states ccid3hcrx_state:8;
u32 ccid3hcrx_bytes_recv;
ktime_t ccid3hcrx_tstamp_last_feedback;
- ktime_t ccid3hcrx_tstamp_last_ack;
- struct list_head ccid3hcrx_hist;
+ struct tfrc_rx_hist ccid3hcrx_hist;
struct list_head ccid3hcrx_li_hist;
u16 ccid3hcrx_s;
u32 ccid3hcrx_pinv;
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c
index a5f59af..7e0714a 100644
--- a/net/dccp/ccids/lib/loss_interval.c
+++ b/net/dccp/ccids/lib/loss_interval.c
@@ -129,6 +129,13 @@ static u32 dccp_li_calc_first_li(struct sock *sk,
u16 s, u32 bytes_recv,
u32 previous_x_recv)
{
+/*
+ * FIXME:
+ * Will be rewritten in the upcoming new loss intervals code.
+ * Has to be commented ou because it relies on the old rx history
+ * data structures
+ */
+#if 0
struct tfrc_rx_hist_entry *entry, *next, *tail = NULL;
u32 x_recv, p;
suseconds_t rtt, delta;
@@ -216,10 +223,10 @@ found:
dccp_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
"loss rate=%u\n", dccp_role(sk), sk, x_recv, p);
- if (p == 0)
- return ~0;
- else
+ if (p != 0)
return 1000000 / p;
+#endif
+ return ~0;
}
void dccp_li_update_li(struct sock *sk,
diff --git a/net/dccp/ccids/lib/packet_history.c b/net/dccp/ccids/lib/packet_history.c
index 255cca1..e197389 100644
--- a/net/dccp/ccids/lib/packet_history.c
+++ b/net/dccp/ccids/lib/packet_history.c
@@ -36,7 +36,9 @@
*/
#include <linux/string.h>
+#include <linux/slab.h>
#include "packet_history.h"
+#include "../../dccp.h"
/**
* tfrc_tx_hist_entry - Simple singly-linked TX history list
@@ -111,154 +113,214 @@ u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head, const u64 seqno,
}
EXPORT_SYMBOL_GPL(tfrc_tx_hist_rtt);
+
+/**
+ * tfrc_rx_hist_index - index to reach n-th entry after loss_start
+ */
+static inline u8 tfrc_rx_hist_index(const struct tfrc_rx_hist *h, const u8 n)
+{
+ return (h->loss_start + n) & TFRC_NDUPACK;
+}
+
+/**
+ * tfrc_rx_hist_last_rcv - entry with highest-received-seqno so far
+ */
+static inline struct tfrc_rx_hist_entry *
+ tfrc_rx_hist_last_rcv(const struct tfrc_rx_hist *h)
+{
+ return h->ring[tfrc_rx_hist_index(h, h->loss_count)];
+}
+
/*
* Receiver History Routines
*/
static struct kmem_cache *tfrc_rx_hist_slab;
-struct tfrc_rx_hist_entry *tfrc_rx_hist_entry_new(const u32 ndp,
- const struct sk_buff *skb,
- const gfp_t prio)
+void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
+ const struct sk_buff *skb,
+ const u32 ndp)
{
- struct tfrc_rx_hist_entry *entry = kmem_cache_alloc(tfrc_rx_hist_slab,
- prio);
-
- if (entry != NULL) {
- const struct dccp_hdr *dh = dccp_hdr(skb);
-
- entry->tfrchrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
- entry->tfrchrx_ccval = dh->dccph_ccval;
- entry->tfrchrx_type = dh->dccph_type;
- entry->tfrchrx_ndp = ndp;
- entry->tfrchrx_tstamp = ktime_get_real();
- }
-
- return entry;
+ struct tfrc_rx_hist_entry *entry = tfrc_rx_hist_last_rcv(h);
+ const struct dccp_hdr *dh = dccp_hdr(skb);
+
+ entry->tfrchrx_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+ entry->tfrchrx_ccval = dh->dccph_ccval;
+ entry->tfrchrx_type = dh->dccph_type;
+ entry->tfrchrx_ndp = ndp;
+ entry->tfrchrx_tstamp = ktime_get_real();
}
-EXPORT_SYMBOL_GPL(tfrc_rx_hist_entry_new);
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_add_packet);
static inline void tfrc_rx_hist_entry_delete(struct tfrc_rx_hist_entry *entry)
{
kmem_cache_free(tfrc_rx_hist_slab, entry);
}
-int tfrc_rx_hist_find_entry(const struct list_head *list, const u64 seq,
- u8 *ccval)
+/**
+ * tfrc_rx_hist_entry - return the n-th history entry after loss_start
+ */
+static inline struct tfrc_rx_hist_entry *
+ tfrc_rx_hist_entry(const struct tfrc_rx_hist *h, const u8 n)
{
- struct tfrc_rx_hist_entry *packet = NULL, *entry;
+ return h->ring[tfrc_rx_hist_index(h, n)];
+}
- list_for_each_entry(entry, list, tfrchrx_node)
- if (entry->tfrchrx_seqno == seq) {
- packet = entry;
- break;
- }
+/**
+ * tfrc_rx_hist_loss_prev - entry with highest-received-seqno before loss was detected
+ */
+static inline struct tfrc_rx_hist_entry *
+ tfrc_rx_hist_loss_prev(const struct tfrc_rx_hist *h)
+{
+ return h->ring[h->loss_start];
+}
+
+/* has the packet contained in skb been seen before? */
+int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb)
+{
+ const u64 seq = DCCP_SKB_CB(skb)->dccpd_seq;
+ int i;
+
+ if (dccp_delta_seqno(tfrc_rx_hist_loss_prev(h)->tfrchrx_seqno, seq) <= 0)
+ return 1;
- if (packet)
- *ccval = packet->tfrchrx_ccval;
+ for (i = 1; i <= h->loss_count; i++)
+ if (tfrc_rx_hist_entry(h, i)->tfrchrx_seqno == seq)
+ return 1;
- return packet != NULL;
+ return 0;
}
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_duplicate);
-EXPORT_SYMBOL_GPL(tfrc_rx_hist_find_entry);
-struct tfrc_rx_hist_entry *
- tfrc_rx_hist_find_data_packet(const struct list_head *list)
+/* initialise loss detection and disable RTT sampling */
+static inline void tfrc_rx_hist_loss_indicated(struct tfrc_rx_hist *h)
{
- struct tfrc_rx_hist_entry *entry, *packet = NULL;
+ h->loss_count = 1;
+}
- list_for_each_entry(entry, list, tfrchrx_node)
- if (entry->tfrchrx_type == DCCP_PKT_DATA ||
- entry->tfrchrx_type == DCCP_PKT_DATAACK) {
- packet = entry;
- break;
- }
+/* indicate whether previously a packet was detected missing */
+static inline int tfrc_rx_hist_loss_pending(const struct tfrc_rx_hist *h)
+{
+ return h->loss_count;
+}
+
+/* any data packets missing between last reception and skb ? */
+int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h,
+ const struct sk_buff *skb, u32 ndp)
+{
+ int delta = dccp_delta_seqno(tfrc_rx_hist_last_rcv(h)->tfrchrx_seqno,
+ DCCP_SKB_CB(skb)->dccpd_seq);
+
+ if (delta > 1 && ndp < delta)
+ tfrc_rx_hist_loss_indicated(h);
- return packet;
+ return tfrc_rx_hist_loss_pending(h);
}
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_new_loss_indicated);
-EXPORT_SYMBOL_GPL(tfrc_rx_hist_find_data_packet);
+int tfrc_rx_hist_alloc(struct tfrc_rx_hist *h)
+{
+ int i;
+
+ for (i = 0; i <= TFRC_NDUPACK; i++) {
+ h->ring[i] = kmem_cache_alloc(tfrc_rx_hist_slab, GFP_ATOMIC);
+ if (h->ring[i] == NULL)
+ goto out_free;
+ }
+
+ h->loss_count = h->loss_start = 0;
+ return 0;
+
+out_free:
+ while (i-- != 0) {
+ kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
+ h->ring[i] = NULL;
+ }
+ return -ENOBUFS;
+}
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_alloc);
-void tfrc_rx_hist_add_packet(struct list_head *rx_list,
- struct list_head *li_list,
- struct tfrc_rx_hist_entry *packet,
- u64 nonloss_seqno)
+void tfrc_rx_hist_purge(struct tfrc_rx_hist *h)
{
- struct tfrc_rx_hist_entry *entry, *next;
- u8 num_later = 0;
-
- list_add(&packet->tfrchrx_node, rx_list);
-
- num_later = TFRC_RECV_NUM_LATE_LOSS + 1;
-
- if (!list_empty(li_list)) {
- list_for_each_entry_safe(entry, next, rx_list, tfrchrx_node) {
- if (num_later == 0) {
- if (after48(nonloss_seqno,
- entry->tfrchrx_seqno)) {
- list_del_init(&entry->tfrchrx_node);
- tfrc_rx_hist_entry_delete(entry);
- }
- } else if (tfrc_rx_hist_entry_data_packet(entry))
- --num_later;
- }
- } else {
- int step = 0;
- u8 win_count = 0; /* Not needed, but lets shut up gcc */
- int tmp;
- /*
- * We have no loss interval history so we need at least one
- * rtt:s of data packets to approximate rtt.
- */
- list_for_each_entry_safe(entry, next, rx_list, tfrchrx_node) {
- if (num_later == 0) {
- switch (step) {
- case 0:
- step = 1;
- /* OK, find next data packet */
- num_later = 1;
- break;
- case 1:
- step = 2;
- /* OK, find next data packet */
- num_later = 1;
- win_count = entry->tfrchrx_ccval;
- break;
- case 2:
- tmp = win_count - entry->tfrchrx_ccval;
- if (tmp < 0)
- tmp += TFRC_WIN_COUNT_LIMIT;
- if (tmp > TFRC_WIN_COUNT_PER_RTT + 1) {
- /*
- * We have found a packet older
- * than one rtt remove the rest
- */
- step = 3;
- } else /* OK, find next data packet */
- num_later = 1;
- break;
- case 3:
- list_del_init(&entry->tfrchrx_node);
- tfrc_rx_hist_entry_delete(entry);
- break;
- }
- } else if (tfrc_rx_hist_entry_data_packet(entry))
- --num_later;
+ int i;
+
+ for (i = 0; i <= TFRC_NDUPACK; ++i)
+ if (h->ring[i] != NULL) {
+ kmem_cache_free(tfrc_rx_hist_slab, h->ring[i]);
+ h->ring[i] = NULL;
}
- }
}
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_purge);
-EXPORT_SYMBOL_GPL(tfrc_rx_hist_add_packet);
+/**
+ * tfrc_rx_hist_rtt_last_s - reference entry to compute RTT samples against
+ */
+static inline struct tfrc_rx_hist_entry *
+ tfrc_rx_hist_rtt_last_s(const struct tfrc_rx_hist *h)
+{
+ return h->ring[0];
+}
-void tfrc_rx_hist_purge(struct list_head *list)
+/**
+ * tfrc_rx_hist_rtt_prev_s: previously suitable (wrt rtt_last_s) RTT-sampling entry
+ */
+static inline struct tfrc_rx_hist_entry *
+ tfrc_rx_hist_rtt_prev_s(const struct tfrc_rx_hist *h)
{
- struct tfrc_rx_hist_entry *entry, *next;
+ return h->ring[h->rtt_sample_prev];
+}
- list_for_each_entry_safe(entry, next, list, tfrchrx_node) {
- list_del_init(&entry->tfrchrx_node);
- tfrc_rx_hist_entry_delete(entry);
+/**
+ * tfrc_rx_hist_sample_rtt - Sample RTT from timestamp / CCVal
+ * Based on ideas presented in RFC 4342, 8.1. Returns 0 if it was not able
+ * to compute a sample with given data - calling function should check this.
+ */
+u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h, const struct sk_buff *skb)
+{
+ u32 sample = 0,
+ delta_v = SUB16(dccp_hdr(skb)->dccph_ccval,
+ tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
+
+ if (delta_v < 1 || delta_v > 4) { /* unsuitable CCVal delta */
+ if (h->rtt_sample_prev == 2) { /* previous candidate stored */
+ sample = SUB16(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
+ tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
+ if (sample)
+ sample = 4 / sample *
+ ktime_us_delta(tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_tstamp,
+ tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp);
+ else /*
+ * FIXME: This condition is in principle not
+ * possible but occurs when CCID is used for
+ * two-way data traffic. I have tried to trace
+ * it, but the cause does not seem to be here.
+ */
+ DCCP_BUG("please report to dccp@vger.kernel.org"
+ " => prev = %u, last = %u",
+ tfrc_rx_hist_rtt_prev_s(h)->tfrchrx_ccval,
+ tfrc_rx_hist_rtt_last_s(h)->tfrchrx_ccval);
+ } else if (delta_v < 1) {
+ h->rtt_sample_prev = 1;
+ goto keep_ref_for_next_time;
+ }
+
+ } else if (delta_v == 4) /* optimal match */
+ sample = ktime_to_us(net_timedelta(tfrc_rx_hist_rtt_last_s(h)->tfrchrx_tstamp));
+ else { /* suboptimal match */
+ h->rtt_sample_prev = 2;
+ goto keep_ref_for_next_time;
}
-}
-EXPORT_SYMBOL_GPL(tfrc_rx_hist_purge);
+ if (unlikely(sample > DCCP_SANE_RTT_MAX)) {
+ DCCP_WARN("RTT sample %u too large, using max\n", sample);
+ sample = DCCP_SANE_RTT_MAX;
+ }
+
+ h->rtt_sample_prev = 0; /* use current entry as next reference */
+keep_ref_for_next_time:
+
+ return sample;
+}
+EXPORT_SYMBOL_GPL(tfrc_rx_hist_sample_rtt);
__init int packet_history_init(void)
{
diff --git a/net/dccp/ccids/lib/packet_history.h b/net/dccp/ccids/lib/packet_history.h
index 5b0b983..3dfd182 100644
--- a/net/dccp/ccids/lib/packet_history.h
+++ b/net/dccp/ccids/lib/packet_history.h
@@ -37,15 +37,9 @@
#define _DCCP_PKT_HIST_
#include <linux/ktime.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include "tfrc.h"
+#include <linux/types.h>
-/* Number of later packets received before one is considered lost */
-#define TFRC_RECV_NUM_LATE_LOSS 3
-
-#define TFRC_WIN_COUNT_PER_RTT 4
-#define TFRC_WIN_COUNT_LIMIT 16
+struct sk_buff;
struct tfrc_tx_hist_entry;
@@ -54,11 +48,20 @@ extern void tfrc_tx_hist_purge(struct tfrc_tx_hist_entry **headp);
extern u32 tfrc_tx_hist_rtt(struct tfrc_tx_hist_entry *head,
const u64 seqno, const ktime_t now);
-/*
- * Receiver History data structures and declarations
+/* Subtraction a-b modulo-16, respects circular wrap-around */
+#define SUB16(a, b) (((a) + 16 - (b)) & 0xF)
+
+/* Number of packets to wait after a missing packet (RFC 4342, 6.1) */
+#define TFRC_NDUPACK 3
+
+/**
+ * tfrc_rx_hist_entry - Store information about a single received packet
+ * @tfrchrx_seqno: DCCP packet sequence number
+ * @tfrchrx_ccval: window counter value of packet (RFC 4342, 8.1)
+ * @tfrchrx_ndp: the NDP count (if any) of the packet
+ * @tfrchrx_tstamp: actual receive time of packet
*/
struct tfrc_rx_hist_entry {
- struct list_head tfrchrx_node;
u64 tfrchrx_seqno:48,
tfrchrx_ccval:4,
tfrchrx_type:4;
@@ -66,42 +69,30 @@ struct tfrc_rx_hist_entry {
ktime_t tfrchrx_tstamp;
};
-extern struct tfrc_rx_hist_entry *
- tfrc_rx_hist_entry_new(const u32 ndp,
- const struct sk_buff *skb,
- const gfp_t prio);
-
-static inline struct tfrc_rx_hist_entry *
- tfrc_rx_hist_head(struct list_head *list)
-{
- struct tfrc_rx_hist_entry *head = NULL;
-
- if (!list_empty(list))
- head = list_entry(list->next, struct tfrc_rx_hist_entry,
- tfrchrx_node);
- return head;
-}
-
-extern int tfrc_rx_hist_find_entry(const struct list_head *list, const u64 seq,
- u8 *ccval);
-extern struct tfrc_rx_hist_entry *
- tfrc_rx_hist_find_data_packet(const struct list_head *list);
-
-extern void tfrc_rx_hist_add_packet(struct list_head *rx_list,
- struct list_head *li_list,
- struct tfrc_rx_hist_entry *packet,
- u64 nonloss_seqno);
-
-extern void tfrc_rx_hist_purge(struct list_head *list);
+/**
+ * tfrc_rx_hist - RX history structure for TFRC-based protocols
+ *
+ * @ring: Packet history for RTT sampling and loss detection
+ * @loss_count: Number of entries in circular history
+ * @loss_start: Movable index (for loss detection)
+ * @rtt_sample_prev: Used during RTT sampling, points to candidate entry
+ */
+struct tfrc_rx_hist {
+ struct tfrc_rx_hist_entry *ring[TFRC_NDUPACK + 1];
+ u8 loss_count:2,
+ loss_start:2;
+#define rtt_sample_prev loss_start
+};
-static inline int
- tfrc_rx_hist_entry_data_packet(const struct tfrc_rx_hist_entry *entry)
-{
- return entry->tfrchrx_type == DCCP_PKT_DATA ||
- entry->tfrchrx_type == DCCP_PKT_DATAACK;
-}
+extern void tfrc_rx_hist_add_packet(struct tfrc_rx_hist *h,
+ const struct sk_buff *skb, const u32 ndp);
-extern u64 tfrc_rx_hist_detect_loss(struct list_head *rx_list,
- struct list_head *li_list, u8 *win_loss);
+extern int tfrc_rx_hist_duplicate(struct tfrc_rx_hist *h, struct sk_buff *skb);
+extern int tfrc_rx_hist_new_loss_indicated(struct tfrc_rx_hist *h,
+ const struct sk_buff *skb, u32 ndp);
+extern u32 tfrc_rx_hist_sample_rtt(struct tfrc_rx_hist *h,
+ const struct sk_buff *skb);
+extern int tfrc_rx_hist_alloc(struct tfrc_rx_hist *h);
+extern void tfrc_rx_hist_purge(struct tfrc_rx_hist *h);
#endif /* _DCCP_PKT_HIST_ */
--
1.5.3.4
^ permalink raw reply related
* Re: [PATCH net-2.6.25 10/11][INET] Eliminate difference in actions of sysctl and proc handler for conf.all.forwarding
From: Pavel Emelyanov @ 2007-12-06 12:31 UTC (permalink / raw)
To: Herbert Xu; +Cc: David Miller, netdev, devel
In-Reply-To: <E1J04N1-0006uU-00@gondolin.me.apana.org.au>
Herbert Xu wrote:
> David Miller <davem@davemloft.net> wrote:
>> The user is pretty much screwed in one way or the other.
>> For example:
>>
>> 1) If 'default' propagates to all devices, any specific
>> setting for a device is lost.
>>
>> 2) If 'default' does not propagate, there is no way to
>> have 'default' influence devices which have already
>> been loaded.
>
> Well the way it works on IPv4 currently (for most options) is
> that we'll propagate default settings to a device until either:
>
> 1) the user modifies the setting for that device;
> 2) or that an IPv4 address has been added to the device.
BTW, this is not 100% true. Look, in rtm_to_ifaddr()
I see the following code flow:
ipv4_devconf_setall(in_dev);
ifa = inet_alloc_ifa();
if (ifa == NULL) {
/*
* A potential indev allocation can be left alive, it stays
* assigned to its device and is destroy with it.
*/
err = -ENOBUFS;
goto errout;
}
if we fail to allocate the ifa (hard to happen, but), we will
make this device not to accept the default propagation.
If this is a relevant note, I can prepare the patch.
> 2) was done to preserve backwards compatibility as the controls
> were previously only available after address addition and we did
> not propagate default settings in that case..
>
> We could easily extend this so that the default propagation
> worked until the user modified the setting, with an ioctl to
> revert to the current behaviour for compatibility.
>
> Cheers,
^ permalink raw reply
* Re: sockets affected by IPsec always block (2.6.23)
From: Stefan Rompf @ 2007-12-06 12:30 UTC (permalink / raw)
To: David Miller; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <20071206.033909.76192198.davem@davemloft.net>
Am Donnerstag, 6. Dezember 2007 12:39 schrieb David Miller:
> > Because you just will put enough RAM modules into you server when
> > setting up a scalable system.
>
> This suggestion is avoiding the important semantic issue, and
> won't lead to a real discussion of the core problem.
When writing applications for unix operating systems, it is known since ages
that stuff can be swapped out and that even things like memory accesses can
block. So it does not really surprise when a system call has to wait for
memory - just imagine the kernel code for connect() could be and has been
swapped out.
Even with moderate swap activity, this memory should be available in much less
than one second. If on the other hand the system is already threshing, it is
no difference if it does so within connect() or while reaching the connect()
system call in the application flow.
Btw, this is where admin responsibility to size their systems kicks in.
So where I would draw the line: connect() is clearly a network related
function. Therefore, if a nonblocking connect() has to sleep for a local,
controllable resource like memory to become available, this is ok. Maybe it
shouldn't wait for a 128MB buffer if someone configured such an abonimation,
haven't thought deeply about that. But when being told not to wait the
connection to complete, it should never ever wait for another network related
activity like IPSEC SA setup to complete, especially not for hours.
IMHO this is what developers expect, and is also consistent with the fact that
POSIX does not define O_NONBLOCK behaviour for local files.
Stefan
^ permalink raw reply
* Re: [BRIDGE] warning message when add an interface to bridge
From: Chung-Chi Lo @ 2007-12-06 12:18 UTC (permalink / raw)
To: Eric W. Biederman; +Cc: Stephen Hemminger, netdev
In-Reply-To: <m1odd4tlay.fsf@ebiederm.dsl.xmission.com>
Thanks. After applying this patch, the warning message is gone.
[PATCH] net: Fix running without sysfs
On Dec 6, 2007 2:00 PM, Eric W. Biederman <ebiederm@xmission.com> wrote:
>
> Stephen Hemminger <shemminger@linux-foundation.org> writes:
>
> > On Wed, 5 Dec 2007 10:44:17 +0800
> > "Chung-Chi Lo" <linolo@gmail.com> wrote:
> >
> >> My kernel is Linxu 2.6.22.1. SYSFS is off.
> >> When adding an interface to bridge, console will show WARNING message.
> >> If turn SYSFS to on, then the WARNING message is gone.
> >> Any suggestion how to debug this problem? Thanks.
> >>
> >> # ifconfig eth0 0.0.0.0
> >> eth0: starting interface.
> >> # brctl addbr br0
> >> # brctl addif br0 eth0
> >> WARNING: at lib/kref.c:33 kref_get()
> >> Call Trace:
> >> [<80027844>] dump_stack+0x8/0x38
> >> [<8011f348>] kref_get+0xdc/0xe4
> >> [<8011ee20>] kobject_get+0x20/0x34
> >> [<8011e910>] kobject_shadow_add+0x5c/0x170
> >> [<8011ea34>] kobject_add+0x10/0x20
> >> [<8020aac0>] br_add_if+0xb4/0x1b4
> >> [<8020b354>] add_del_if+0x5c/0x118
> >> [<8020bcc4>] br_dev_ioctl+0x6c/0x88
> >> [<80182edc>] dev_ifsioc+0x334/0x3c0
> >> [<80183184>] dev_ioctl+0x21c/0x2ec
> >> [<8016f76c>] sock_ioctl+0x130/0x2e4
> >> [<800b3b2c>] do_ioctl+0x6c/0x84
> >> [<800b3d40>] vfs_ioctl+0x80/0x248
> >> [<800b3f58>] sys_ioctl+0x50/0x98
> >> [<8002a8a8>] stack_done+0x20/0x3c
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe netdev" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
> > This is an an artifact of the kobject_shadow code which was reverted in later
> > kernels.
> > It is gone in 2.6.23
>
> I don't think it was the kobject_shadow, but rather we didn't initialize the kref
> or something like that in net/core/dev.c
>
> I believe commit 8b41d1887db718be9a2cd9e18c58ce25a4c7fd93 was the fix.
>
> Disabling sysfs can be a fun exercise in finding corner case bugs right now.
>
> Eric
>
>
--
Lino, Chung-Chi Lo
^ permalink raw reply
* [PATCH 2.6.25] multiple namespaces in the all dst_ifdown routines
From: Denis V. Lunev @ 2007-12-06 12:17 UTC (permalink / raw)
To: davem; +Cc: containers, devel, netdev
move dst entries to a namespace loopback to catch refcounting leaks.
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
net/core/dst.c | 4 ++--
net/ipv4/route.c | 5 +++--
net/ipv4/xfrm4_policy.c | 3 ++-
net/ipv6/route.c | 7 +++++--
net/ipv6/xfrm6_policy.c | 3 ++-
net/xfrm/xfrm_policy.c | 2 +-
6 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/net/core/dst.c b/net/core/dst.c
index f538061..5c6cfc4 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -279,11 +279,11 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
if (!unregister) {
dst->input = dst->output = dst_discard;
} else {
- dst->dev = init_net.loopback_dev;
+ dst->dev = dst->dev->nd_net->loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
if (dst->neighbour && dst->neighbour->dev == dev) {
- dst->neighbour->dev = init_net.loopback_dev;
+ dst->neighbour->dev = dst->dev;
dev_put(dev);
dev_hold(dst->neighbour->dev);
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index dae1290..e4aa97e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1425,8 +1425,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
{
struct rtable *rt = (struct rtable *) dst;
struct in_device *idev = rt->idev;
- if (dev != init_net.loopback_dev && idev && idev->dev == dev) {
- struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev);
+ if (dev != dev->nd_net->loopback_dev && idev && idev->dev == dev) {
+ struct in_device *loopback_idev =
+ in_dev_get(dev->nd_net->loopback_dev);
if (loopback_idev) {
rt->idev = loopback_idev;
in_dev_put(idev);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 19fdf8a..e086260 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -216,7 +216,8 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt.idev->dev == dev) {
- struct in_device *loopback_idev = in_dev_get(init_net.loopback_dev);
+ struct in_device *loopback_idev =
+ in_dev_get(dev->nd_net->loopback_dev);
BUG_ON(!loopback_idev);
do {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index e36cac9..e757a3c 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -216,9 +216,12 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
{
struct rt6_info *rt = (struct rt6_info *)dst;
struct inet6_dev *idev = rt->rt6i_idev;
+ struct net_device *loopback_dev =
+ dev->nd_net->loopback_dev;
- if (dev != init_net.loopback_dev && idev != NULL && idev->dev == dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev);
+ if (dev != loopback_dev && idev != NULL && idev->dev == dev) {
+ struct inet6_dev *loopback_idev =
+ in6_dev_get(loopback_dev);
if (loopback_idev != NULL) {
rt->rt6i_idev = loopback_idev;
in6_dev_put(idev);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index cc0d151..7b360ea 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -233,7 +233,8 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
xdst = (struct xfrm_dst *)dst;
if (xdst->u.rt6.rt6i_idev->dev == dev) {
- struct inet6_dev *loopback_idev = in6_dev_get(init_net.loopback_dev);
+ struct inet6_dev *loopback_idev =
+ in6_dev_get(dev->nd_net->loopback_dev);
BUG_ON(!loopback_idev);
do {
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index a9ac748..900f6b6 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1932,7 +1932,7 @@ static int stale_bundle(struct dst_entry *dst)
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
{
while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
- dst->dev = init_net.loopback_dev;
+ dst->dev = dev->nd_net->loopback_dev;
dev_hold(dst->dev);
dev_put(dev);
}
--
1.5.3.rc5
^ permalink raw reply related
* Re: sockets affected by IPsec always block (2.6.23)
From: David Miller @ 2007-12-06 11:39 UTC (permalink / raw)
To: stefan; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <200712061235.06025.stefan@loplof.de>
From: Stefan Rompf <stefan@loplof.de>
Date: Thu, 6 Dec 2007 12:35:05 +0100
> Because you just will put enough RAM modules into you server when
> setting up a scalable system.
This suggestion is avoiding the important semantic issue, and
won't lead to a real discussion of the core problem.
^ permalink raw reply
* Re: sockets affected by IPsec always block (2.6.23)
From: Stefan Rompf @ 2007-12-06 11:35 UTC (permalink / raw)
To: David Miller; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <20071206.031302.201608796.davem@davemloft.net>
Am Donnerstag, 6. Dezember 2007 12:13 schrieb David Miller:
> And that's why this is a grey area. Why is waiting for memory
> allocation on a O_NONBLOCK socket OK but waiting for IPSEC route
> resolution is not?
Because you just will put enough RAM modules into you server when setting up a
scalable system. Local resource, managable by the admin. What you cannot
control in many cases is the network connection to the remote node. Simon
Arlott has been talking about an 8 hour network outage.
Stefan
^ permalink raw reply
* Re: [PATCH net-2.6.25 10/11][INET] Eliminate difference in actions of sysctl and proc handler for conf.all.forwarding
From: David Miller @ 2007-12-06 11:14 UTC (permalink / raw)
To: herbert; +Cc: xemul, netdev, devel
In-Reply-To: <20071206110601.GA30402@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Thu, 6 Dec 2007 22:06:01 +1100
> On Wed, Dec 05, 2007 at 09:39:33PM -0800, David Miller wrote:
> >
> > But we go back again to the question of how to get this "current
> > behavior" setting instantiated early enough. So much stuff happens
> > via initrd's etc. before the real userland has a change to run things,
> > read setting from the real filesystem config giles, in order to change
> > this.
>
> Perhaps a boot time command line option?
It's not pleasant but it would indeed work.
^ permalink raw reply
* Re: [Patch] net/xfrm/xfrm_policy.c: Some small improvements
From: David Miller @ 2007-12-06 11:14 UTC (permalink / raw)
To: xiyou.wangcong; +Cc: linux-kernel, herbert, akpm, netdev
In-Reply-To: <20071206110123.GB2469@hacking>
From: WANG Cong <xiyou.wangcong@gmail.com>
Date: Thu, 6 Dec 2007 19:01:23 +0800
>
> This patch contains the following changes.
>
> - Use 'bool' instead of 'int' for booleans.
> - Use 'size_t' instead of 'int' for 'sizeof' return value.
> - Some style fixes.
>
> Cc: Herbert Xu <herbert@gondor.apana.org.au>
> Cc: David Miller <davem@davemloft.net>
> Signed-off-by: WANG Cong <xiyou.wangcong@gmail.com>
Normally I would let a patch like this sit in my mailbox
for a week and then delete it.
But this time I'll just let you know up front that I
don't see much value in this patch. It is not a clear
improvement to replace int's with bool's in my mind and
the other changes are just whitespace changes.
And thus I can delete the patch from my mailbox
immediately :-)
Sorry.
^ permalink raw reply
* Re: sockets affected by IPsec always block (2.6.23)
From: David Miller @ 2007-12-06 11:13 UTC (permalink / raw)
To: stefan; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <200712061156.48810.stefan@loplof.de>
From: Stefan Rompf <stefan@loplof.de>
Date: Thu, 6 Dec 2007 11:56:48 +0100
> Am Donnerstag, 6. Dezember 2007 09:53 schrieb David Miller:
>
> > > I think the words "shall fail" and "immediately" are quite clear.
> >
> > They are, but the context in which they apply is vague.
>
> "socket is connection-mode" => SOCK_STREAM
I meant whether "immediately" mean in reference to socket
state or includes auxiliary things like route lookups.
When you do a non-blocking write on a socket, things like
memory allocations can block, potentially for a long time.
It is an example where there are definite boundaries to where
the non-blocking'ness applies.
And therefore it is not so cut and dry and you present this
issue.
> The reason why I'm pushing this issue another time is that I know quite a
> bit about system level application development. A very typical design pattern
> for non-naive single or multi threaded programs is that they set all
> communication sockets to be nonblocking and use a select()/epoll() based loop
> to dispatch IO. This often includes initiating a TCP connect() and
> asynchronously waiting for it to finish or fail from the main loop.
>
> The dangerous situation here is that in 99% of all cases things will just work
> because the phase 2 SA exists. In 0.8%, the SA will be established in <1 sec.
> However, in the rest of time the server application that you have considered
> to be stable will end up sleeping with all threads in a connect() call that
> is supposed to return immediatly.
And that connect() call can hang for a long time due to any memory
allocation done in the connect() path.
You are not avoiding blocking by setting O_NONBLOCK on the socket, it
is quite foolhardy to think that it does so unilaterally.
And that's why this is a grey area. Why is waiting for memory
allocation on a O_NONBLOCK socket OK but waiting for IPSEC route
resolution is not?
^ permalink raw reply
* Re: [PATCH net-2.6.25 10/11][INET] Eliminate difference in actions of sysctl and proc handler for conf.all.forwarding
From: Herbert Xu @ 2007-12-06 11:06 UTC (permalink / raw)
To: David Miller; +Cc: xemul, netdev, devel
In-Reply-To: <20071205.213933.40987728.davem@davemloft.net>
On Wed, Dec 05, 2007 at 09:39:33PM -0800, David Miller wrote:
>
> But we go back again to the question of how to get this "current
> behavior" setting instantiated early enough. So much stuff happens
> via initrd's etc. before the real userland has a change to run things,
> read setting from the real filesystem config giles, in order to change
> this.
Perhaps a boot time command line option?
Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* [Patch] net/xfrm/xfrm_policy.c: Some small improvements
From: WANG Cong @ 2007-12-06 11:01 UTC (permalink / raw)
To: LKML; +Cc: David Miller, Herbert Xu, Andrew Morton, netdev
This patch contains the following changes.
- Use 'bool' instead of 'int' for booleans.
- Use 'size_t' instead of 'int' for 'sizeof' return value.
- Some style fixes.
Cc: Herbert Xu <herbert@gondor.apana.org.au>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: WANG Cong <xiyou.wangcong@gmail.com>
---
net/xfrm/xfrm_policy.c | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 5d6a81d..311b08f 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -476,17 +476,17 @@ static u32 xfrm_gen_index(u8 type, int dir)
struct hlist_head *list;
struct xfrm_policy *p;
u32 idx;
- int found;
+ bool found;
idx = (idx_generator | dir);
idx_generator += 8;
if (idx == 0)
idx = 8;
list = xfrm_policy_byidx + idx_hash(idx);
- found = 0;
+ found = false;
hlist_for_each_entry(p, entry, list, byidx) {
if (p->index == idx) {
- found = 1;
+ found = true;
break;
}
}
@@ -499,8 +499,8 @@ static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s
{
u32 *p1 = (u32 *) s1;
u32 *p2 = (u32 *) s2;
- int len = sizeof(struct xfrm_selector) / sizeof(u32);
- int i;
+ size_t len = sizeof(struct xfrm_selector) / sizeof(u32);
+ size_t i;
for (i = 0; i < len; i++) {
if (p1[i] != p2[i])
@@ -953,7 +953,7 @@ static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
#ifdef CONFIG_XFRM_SUB_POLICY
end:
#endif
- if ((*objp = (void *) pol) != NULL)
+ if ((*objp = pol) != NULL)
*obj_refp = &pol->refcnt;
return err;
}
@@ -1137,7 +1137,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,
xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);
xfrm_address_t tmp;
- for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
+ for (nx = 0, i = 0; i < policy->xfrm_nr; i++) {
struct xfrm_state *x;
xfrm_address_t *remote = daddr;
xfrm_address_t *local = saddr;
@@ -1395,7 +1395,7 @@ free_dst:
}
static int inline
-xfrm_dst_alloc_copy(void **target, void *src, int size)
+xfrm_dst_alloc_copy(void **target, void *src, size_t size)
{
if (!*target) {
*target = kmalloc(size, GFP_ATOMIC);
@@ -1554,7 +1554,7 @@ restart:
#endif
nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family);
- if (unlikely(nx<0)) {
+ if (unlikely(nx < 0)) {
err = nx;
if (err == -EAGAIN && sysctl_xfrm_larval_drop) {
/* EREMOTE tells the caller to generate
@@ -1688,7 +1688,8 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x,
unsigned short family)
{
if (xfrm_state_kern(x))
- return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
+ return tmpl->optional &&
+ !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family);
return x->id.proto == tmpl->id.proto &&
(x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
(x->props.reqid == tmpl->reqid || !tmpl->reqid) &&
@@ -1777,7 +1778,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
if (skb->sp) {
int i;
- for (i=skb->sp->len-1; i>=0; i--) {
+ for (i = skb->sp->len-1; i >= 0; i--) {
struct xfrm_state *x = skb->sp->xvec[i];
if (!xfrm_selector_match(&x->sel, &fl, family))
return 0;
^ permalink raw reply related
* Re: sockets affected by IPsec always block (2.6.23)
From: Stefan Rompf @ 2007-12-06 10:56 UTC (permalink / raw)
To: David Miller; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <20071206.005344.74817074.davem@davemloft.net>
Am Donnerstag, 6. Dezember 2007 09:53 schrieb David Miller:
> > I think the words "shall fail" and "immediately" are quite clear.
>
> They are, but the context in which they apply is vague.
"socket is connection-mode" => SOCK_STREAM
> I can equally generate examples where the non-blocking behavior you
> are a proponent of would break non-blocking UDP apps during a
> sendmsg() call when we hit IPSEC resolution. Yet similar language on
> blocking semantics exists for sendmsg() in the standards.
I am not a good enough kernel hacker to exactly understand the code flow in
udp_sendmsg(). However, it seems that it first checks destination validity
via ip_route_output_flow() and queues the message then. The sendmsg()
documentation only talks about buffer space. I can see your dilemma.
The reason why I'm pushing this issue another time is that I know quite a
bit about system level application development. A very typical design pattern
for non-naive single or multi threaded programs is that they set all
communication sockets to be nonblocking and use a select()/epoll() based loop
to dispatch IO. This often includes initiating a TCP connect() and
asynchronously waiting for it to finish or fail from the main loop.
The dangerous situation here is that in 99% of all cases things will just work
because the phase 2 SA exists. In 0.8%, the SA will be established in <1 sec.
However, in the rest of time the server application that you have considered
to be stable will end up sleeping with all threads in a connect() call that
is supposed to return immediatly.
> The world is shades of gray, implying anything else is foolhardy and
> that's how I'm handling this.
Even though I consider programmers that ignore the result code on a
nonblocking UDP sendmsg() fools, I agree. May be the best compromise is what
Herbert Xu suggested in <20071205001230.GA11391@gondor.apana.org.au> in this
thread: At least, for connect() O_NONBLOCK ist ALWAYS respected. Because this
is where the chance for breakage is highest.
Stefan
^ permalink raw reply
* Re: TCP event tracking via netlink...
From: Evgeniy Polyakov @ 2007-12-06 10:58 UTC (permalink / raw)
To: David Miller; +Cc: jheffner, ilpo.jarvinen, netdev
In-Reply-To: <20071205.210343.57693750.davem@davemloft.net>
On Wed, Dec 05, 2007 at 09:03:43PM -0800, David Miller (davem@davemloft.net) wrote:
> I think this work is very different.
>
> When I say "state" I mean something more significant than
> CLOSE, ESTABLISHED, etc. which is what Samir's patches are
> tracking.
>
> I'm talking about all of the sequence numbers, SACK information,
> congestion control knobs, etc. whose values are nearly impossible to
> track on a packet to packet basis in order to diagnose problems.
I pointed that work as a possible basis for collecting more info if you
needs including sequence numbers, window sizes and so on.
It just requires a useful structure layout placed, so that one would not
require to recreate the same bits again, so that it could be called from
any place inside the stack.
--
Evgeniy Polyakov
^ permalink raw reply
* Re: TCP event tracking via netlink...
From: David Miller @ 2007-12-06 10:33 UTC (permalink / raw)
To: ilpo.jarvinen; +Cc: netdev
In-Reply-To: <Pine.LNX.4.64.0712051533050.3119@kivilampi-30.cs.helsinki.fi>
From: "Ilpo_Järvinen" <ilpo.jarvinen@helsinki.fi>
Date: Thu, 6 Dec 2007 01:18:28 +0200 (EET)
> On Wed, 5 Dec 2007, David Miller wrote:
>
> > I assume you're using something like carefully crafted printk's,
> > kprobes, or even ad-hoc statistic counters. That's what I used to do
> > :-)
>
> No, that's not at all what I do :-). I usually look time-seq graphs
> expect for the cases when I just find things out by reading code (or
> by just thinking of it).
Can you briefly detail what graph tools and command lines
you are using?
The last time I did graphing to analyze things, the tools
were hit-or-miss.
> Much of the info is available in tcpdump already, it's just hard to read
> without graphing it first because there are some many overlapping things
> to track in two-dimensional space.
>
> ...But yes, I have to admit that couple of problems come to my mind
> where having some variable from tcp_sock would have made the problem
> more obvious.
The most important are the cwnd and ssthresh, which you could guess
using graphs but it is important to know on a packet to packet
basis why we might have sent a packet or not because this has
rippling effects down the rest of the RTT.
> Not sure what is the benefit of having distributions with it because
> those people hardly report problems anyway to here, they're just too
> happy with TCP performance unless we print something to their logs,
> which implies that we must setup a *_ON() condition :-(.
That may be true, but if we could integrate the information with
tcpdumps, we could gather internal state using tools the user
already has available.
Imagine if tcpdump printed out:
02:26:14.865805 IP $SRC > $DEST: . 11226:12686(1460) ack 0 win 108
ss_thresh: 129 cwnd: 133 packets_out: 132
or something like that.
> Some problems are simply such that things cannot be accurately verified
> without high processing overhead until it's far too late (eg skb bits vs
> *_out counters). Maybe we should start to build an expensive state
> validator as well which would automatically check invariants of the write
> queue and tcp_sock in a straight forward, unoptimized manner? That would
> definately do a lot of work for us, just ask people to turn it on and it
> spits out everything that went wrong :-) (unless they really depend on
> very high-speed things and are therefore unhappy if we scan thousands of
> packets unnecessarily per ACK :-)). ...Early enough! ...That would work
> also for distros but there's always human judgement needed to decide
> whether the bug reporter will be happy when his TCP processing does no
> longer scale ;-).
I think it's useful as a TCP_DEBUG config option or similar, sure.
But sometimes the algorithms are working as designed, it's just that
they provide poor pipe utilization and CWND analysis embedded inside
of a tcpdump would be one way to see that as well as determine the
flaw in the algorithm.
> ...Hopefully you found any of my comments useful.
Very much so, thanks.
I put together a sample implementation anyways just to show the idea,
against net-2.6.25 below.
It is untested since I didn't write the userland app yet to see that
proper things get logged. Basically you could run a daemon that
writes per-connection traces into files based upon the incoming
netlink events. Later, using the binary pcap file and these traces,
you can piece together traces like the above using the timestamps
etc. to match up pcap packets to ones from the TCP logger.
The userland tools could do analysis and print pre-cooked state diff
logs, like "this ACK raised CWND by one" or whatever else you wanted
to know.
It's nice that an expert like you can look at graphs and understand,
but we'd like to create more experts and besides reading code one
way to become an expert is to be able to extrace live real data
from the kernel's working state and try to understand how things
got that way. This information is permanently lost currently.
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 56342c3..c0e61d0 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -170,6 +170,47 @@ struct tcp_md5sig {
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
};
+/* TCP netlink event logger. */
+struct tcp_log_key {
+ union {
+ __be32 a4;
+ __be32 a6[4];
+ } saddr, daddr;
+ __be16 sport;
+ __be16 dport;
+ unsigned short family;
+ unsigned short __pad;
+};
+
+struct tcp_log_stamp {
+ __u32 tv_sec;
+ __u32 tv_usec;
+};
+
+struct tcp_log_payload {
+ struct tcp_log_key key;
+ struct tcp_log_stamp stamp;
+ struct tcp_info info;
+};
+
+enum {
+ TCP_LOG_A_UNSPEC = 0,
+ __TCP_LOG_A_MAX,
+};
+#define TCP_LOG_A_MAX (__TCP_LOG_A_MAX - 1)
+
+#define TCP_LOG_GENL_NAME "tcp_log"
+#define TCP_LOG_GENL_VERSION 1
+
+enum {
+ TCP_LOG_CMD_UNSPEC = 0,
+ TCP_LOG_CMD_HELLO,
+ TCP_LOG_CMD_GOODBYE,
+ TCP_LOG_CMD_EVENT,
+ __TCP_LOG_CMD_MAX,
+};
+#define TCP_LOG_CMD_MAX (__TCP_LOG_CMD_MAX - 1)
+
#ifdef __KERNEL__
#include <linux/skbuff.h>
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 9dbed0b..5ac82ea 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1730,6 +1730,19 @@ struct tcp_request_sock_ops {
#endif
};
+#define TCP_LOG_PID_INACTIVE -1
+extern int tcp_log_pid;
+
+extern void tcp_do_log(struct sock *sk, ktime_t stamp);
+
+static inline void tcp_log(struct sock *sk, ktime_t stamp)
+{
+ if (likely(tcp_log_pid == TCP_LOG_PID_INACTIVE))
+ return;
+
+ tcp_do_log(sk, stamp);
+}
+
extern void tcp_v4_init(struct net_proto_family *ops);
extern void tcp_init(void);
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index ad40ef3..fa0cc1d 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -7,7 +7,7 @@ obj-y := route.o inetpeer.o protocol.o \
ip_output.o ip_sockglue.o inet_hashtables.o \
inet_timewait_sock.o inet_connection_sock.o \
tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
- tcp_minisocks.o tcp_cong.o \
+ tcp_minisocks.o tcp_cong.o tcp_log.o \
datagram.o raw.o udp.o udplite.o \
arp.o icmp.o devinet.o af_inet.o igmp.o \
fib_frontend.o fib_semantics.o \
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c5fba12..a51cbd2 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -4577,6 +4577,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
struct tcphdr *th, unsigned len)
{
struct tcp_sock *tp = tcp_sk(sk);
+ ktime_t stamp = skb->tstamp;
/*
* Header prediction.
@@ -4657,6 +4658,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
tcp_ack(sk, skb, 0);
__kfree_skb(skb);
tcp_data_snd_check(sk);
+ tcp_log(sk, stamp);
return 0;
} else { /* Header too small */
TCP_INC_STATS_BH(TCP_MIB_INERRS);
@@ -4748,6 +4750,7 @@ no_ack:
__kfree_skb(skb);
else
sk->sk_data_ready(sk, 0);
+ tcp_log(sk, stamp);
return 0;
}
}
@@ -4800,6 +4803,7 @@ slow_path:
TCP_INC_STATS_BH(TCP_MIB_INERRS);
NET_INC_STATS_BH(LINUX_MIB_TCPABORTONSYN);
tcp_reset(sk);
+ tcp_log(sk, stamp);
return 1;
}
@@ -4817,6 +4821,7 @@ step5:
tcp_data_snd_check(sk);
tcp_ack_snd_check(sk);
+ tcp_log(sk, stamp);
return 0;
csum_error:
@@ -4824,6 +4829,7 @@ csum_error:
discard:
__kfree_skb(skb);
+ tcp_log(sk, stamp);
return 0;
}
--- a/net/ipv4/tcp_log.c 2007-10-24 01:07:28.000000000 -0700
+++ b/net/ipv4/tcp_log.c 2007-12-06 01:06:26.000000000 -0800
@@ -0,0 +1,149 @@
+/* tcp_log.c: Netlink based TCP state change logger.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+
+#include <net/genetlink.h>
+#include <net/inet_sock.h>
+#include <net/tcp.h>
+
+static struct genl_family tcp_log_family = {
+ .id = GENL_ID_GENERATE,
+ .name = TCP_LOG_GENL_NAME,
+ .version = TCP_LOG_GENL_VERSION,
+ .hdrsize = sizeof(struct tcp_log_payload),
+ .maxattr = TCP_LOG_A_MAX,
+};
+
+static unsigned int tcp_log_seqnum;
+
+int tcp_log_pid = TCP_LOG_PID_INACTIVE;
+EXPORT_SYMBOL(tcp_log_pid);
+
+static int tcp_log_hello(struct sk_buff *skb, struct genl_info *info)
+{
+ tcp_log_pid = info->snd_pid;
+ return 0;
+}
+
+static int tcp_log_goodbye(struct sk_buff *skb, struct genl_info *info)
+{
+ tcp_log_pid = TCP_LOG_PID_INACTIVE;
+ return 0;
+}
+
+static struct genl_ops tcp_log_hello_ops = {
+ .cmd = TCP_LOG_CMD_HELLO,
+ .doit = tcp_log_hello,
+};
+
+static struct genl_ops tcp_log_goodbye_ops = {
+ .cmd = TCP_LOG_CMD_GOODBYE,
+ .doit = tcp_log_goodbye,
+};
+
+static void fill_key(struct tcp_log_key *key, struct sock *sk)
+{
+ struct inet_sock *inet = inet_sk(sk);
+ struct ipv6_pinfo *np = inet6_sk(sk);
+
+ switch (sk->sk_family) {
+ case AF_INET:
+ key->saddr.a4 = inet->saddr;
+ key->daddr.a4 = inet->daddr;
+ break;
+ case AF_INET6:
+ memcpy(&key->saddr.a6, &np->saddr, sizeof(key->saddr.a6));
+ memcpy(&key->daddr.a6, &np->daddr, sizeof(key->daddr.a6));
+ break;
+ default:
+ BUG();
+ break;
+ }
+ key->sport = inet->sport;
+ key->dport = inet->dport;
+}
+
+void tcp_do_log(struct sock *sk, ktime_t stamp)
+{
+ struct tcp_log_payload *p;
+ struct sk_buff *skb;
+ struct timeval tv;
+ void *data;
+ int size;
+
+ size = nla_total_size(sizeof(struct tcp_log_payload));
+ skb = genlmsg_new(size, GFP_ATOMIC);
+ if (!skb)
+ return;
+
+ data = genlmsg_put(skb, 0, tcp_log_seqnum++,
+ &tcp_log_family, 0, TCP_LOG_CMD_EVENT);
+ if (!data) {
+ nlmsg_free(skb);
+ return;
+ }
+ p = data;
+
+ fill_key(&p->key, sk);
+
+ if (stamp.tv64)
+ tv = ktime_to_timeval(stamp);
+ else
+ do_gettimeofday(&tv);
+
+ p->stamp.tv_sec = tv.tv_sec;
+ p->stamp.tv_usec = tv.tv_usec;
+
+ tcp_get_info(sk, &p->info);
+
+ if (genlmsg_end(skb, data) < 0) {
+ nlmsg_free(skb);
+ return;
+ }
+
+ genlmsg_unicast(skb, tcp_log_pid);
+}
+EXPORT_SYMBOL(tcp_do_log);
+
+static int __init tcp_log_init(void)
+{
+ int err = genl_register_family(&tcp_log_family);
+
+ if (err)
+ return err;
+
+ err = genl_register_ops(&tcp_log_family, &tcp_log_hello_ops);
+ if (err)
+ goto out_unregister_family;
+
+ err = genl_register_ops(&tcp_log_family, &tcp_log_goodbye_ops);
+ if (err)
+ goto out_unregister_hello;
+
+ return 0;
+
+out_unregister_hello:
+ genl_unregister_ops(&tcp_log_family, &tcp_log_hello_ops);
+
+out_unregister_family:
+ genl_unregister_family(&tcp_log_family);
+
+ return err;
+}
+
+static void __exit tcp_log_exit(void)
+{
+ genl_unregister_ops(&tcp_log_family, &tcp_log_goodbye_ops);
+ genl_unregister_ops(&tcp_log_family, &tcp_log_hello_ops);
+ genl_unregister_family(&tcp_log_family);
+}
+
+module_init(tcp_log_init);
+module_exit(tcp_log_exit);
^ permalink raw reply related
* Re: TCP event tracking via netlink...
From: David Miller @ 2007-12-06 10:20 UTC (permalink / raw)
To: shemminger; +Cc: joe, ilpo.jarvinen, netdev
In-Reply-To: <20071205163338.50aff45d@shemminger-laptop>
From: Stephen Hemminger <shemminger@linux-foundation.org>
Date: Wed, 5 Dec 2007 16:33:38 -0500
> On Wed, 05 Dec 2007 08:53:07 -0800
> Joe Perches <joe@perches.com> wrote:
>
> > > it occurred to me that we might want to do something
> > > like a state change event generator.
> >
> > This could be a basis for an interesting TCP
> > performance tester.
>
> That is what tcpprobe does but it isn't detailed enough to address SACK
> issues.
Indeed, this could be done via the jprobe there.
Silly me I didn't do this in the implementation I whipped
up, which I'll likely correct.
^ permalink raw reply
* Re: [PATCH] remove prototype of ip_rt_advice
From: David Miller @ 2007-12-06 10:19 UTC (permalink / raw)
To: den; +Cc: containers, devel, netdev
In-Reply-To: <20071206101743.GA10673@iris.sw.ru>
From: "Denis V. Lunev" <den@openvz.org>
Date: Thu, 6 Dec 2007 13:17:43 +0300
> ip_rt_advice has been gone, so no need to keep prototype and debug message.
>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
Applied to net-2.6, thanks.
^ permalink raw reply
* [PATCH] remove prototype of ip_rt_advice
From: Denis V. Lunev @ 2007-12-06 10:17 UTC (permalink / raw)
To: davem; +Cc: containers, devel, netdev
ip_rt_advice has been gone, so no need to keep prototype and debug message.
Signed-off-by: Denis V. Lunev <den@openvz.org>
--
diff --git a/include/net/route.h b/include/net/route.h
index f7ce625..59b0b19 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -109,7 +109,6 @@ struct in_device;
extern int ip_rt_init(void);
extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
__be32 src, struct net_device *dev);
-extern void ip_rt_advice(struct rtable **rp, int advice);
extern void rt_cache_flush(int how);
extern int __ip_route_output_key(struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct rtable **, struct flowi *flp);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 134cab5..cefae61 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1198,7 +1198,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
rt->fl.oif);
#if RT_CACHE_DEBUG >= 1
- printk(KERN_DEBUG "ip_rt_advice: redirect to "
+ printk(KERN_DEBUG "ipv4_negative_advice: redirect to "
"%u.%u.%u.%u/%02x dropped\n",
NIPQUAD(rt->rt_dst), rt->fl.fl4_tos);
#endif
^ permalink raw reply related
* Re: bonding sysfs output
From: Ferenc Wagner @ 2007-12-06 10:13 UTC (permalink / raw)
To: Jean Delvare; +Cc: Jay Vosburgh, Andrew Morton, linux-kernel, netdev
In-Reply-To: <20071205235905.7e8ac1b1@hyperion.delvare>
Jean Delvare <khali@linux-fr.org> writes:
> On Mon, 26 Nov 2007 09:29:40 +0100, Wagner Ferenc wrote:
>
>> On the policy side: some files are not applicable to some types of
>> bonds, and return a single linefeed in that case. Except for one
>> single case, which returns 'NA\n'. The patch changes these cases into
>> emtpy files.
>
> IMHO a better approach would be to not create the files at all when
> they make no sense for a given type of bond.
That would require much more in-depth changes in the sysfs code, I'm
afraid. But see also the 5th patch in the series, which reponds to
Jay's suggestion. And as such, goes in the opposite direction.
--
Thanks,
Feri.
^ permalink raw reply
* Re: Reproducible data corruption with sendfile+vsftp - splice regression?
From: Holger Hoffstaette @ 2007-12-06 9:41 UTC (permalink / raw)
To: netdev
In-Reply-To: <20071206011300.GA11792@electric-eye.fr.zoreil.com>
(removing .kernel as it seems to concern netdev only)
On Thu, 06 Dec 2007 02:13:00 +0100, Francois Romieu wrote:
> Francois Romieu <romieu@fr.zoreil.com> :
>> Holger Hoffstaette <holger@wizards.de> : [...]
>> > Should I file this in bugzilla?
>>
>> Yes.
>
> 5326 5585327 5585328 5585329 5585330 5585331 5585332 5585333 5585334
> 5585335 558 5336 5585337 5585338 5585339 5585340 5585341 5585342 5585343
> 5589440 5589441 558
> ^^^^^^^ ^^^^^^^
> 9442 5589443 5589444 5589445 5589446 5589447 5589448 5589449 5589450
> 5589451 558 9452 5589453 5589454 5589455 5589456 5589457 5589458 5589459
> 5589460 5589461 558
>
> It misses 8*4096 bytes.
>
> 8443 9068442 9068441 9068440 9068439 9068438 9068437 9068436 9068435
> 9068434 906 8433 9068432 9068431 9068430 9068429 9068428 9068427 9064330
> 9064329 9064328 906
> ^^^^^^^ ^^^^^^^
> 4327 9064326 9064325 9064324 9064323 9064322 9064321 9064320 9064319
> 9064318 906
>
> Same thing later.
>
> But the amount of data transmitted is fine.
>
> Could you locate the offsets were the sequence is broken ?
According to my hex editor the offsets are:
0x02aa43e4
0x02feb473
0x03142994
0x03765f33
0x03e42ff3
0x03e5079c
0x03e60d9c
0x0451db54
0x0452e7ec
I'll also put all this into bugzilla.
thanks!
Holger
^ permalink raw reply
* Re: Reproducible data corruption with sendfile+vsftp - splice regression?
From: Holger Hoffstaette @ 2007-12-06 9:28 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev
In-Reply-To: <20071205225429.GA10186@electric-eye.fr.zoreil.com>
On Wed, 05 Dec 2007 23:54:29 +0100, Francois Romieu wrote:
> Holger Hoffstaette <holger@wizards.de> : [...]
>> Should I file this in bugzilla?
>
> Yes.
Thanks for responding - will do. I verified with 2.6.24-rc4 (same bug) and
have some new information about this.
Despite my previous posting the corruption is NOT triggered by NAPI. It
may be related, but even without NAPI but tso on again I got corruption,
now also on the gbit client (Thinkpad T60). When ftp'ing to ramdisk with
full speed (at a reasonable ~77 MB/sec) it "often" works, but intermediate
writes that cause the ftp to temporarily slow down reliably cause
corrupted files, so I guess tso gets confused when some kind of throttling
sets in during transfer. That is probably why I first noticed it on the
slow 100mbit client.
Maybe turning off sendfile or NAPI just lead to random success - so far it
really looks like tso on the r8169 is the common cause.
thank you
Holger
^ permalink raw reply
* Re: sockets affected by IPsec always block (2.6.23)
From: David Miller @ 2007-12-06 8:53 UTC (permalink / raw)
To: stefan; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <200712060949.02524.stefan@loplof.de>
From: Stefan Rompf <stefan@loplof.de>
Date: Thu, 6 Dec 2007 09:49:01 +0100
> "If the connection cannot be established immediately and O_NONBLOCK is set for
> the file descriptor for the socket, connect() shall fail and set errno to
> [EINPROGRESS], but the connection request shall not be aborted, and the
> connection shall be established asynchronously."
>
> I think the words "shall fail" and "immediately" are quite clear.
They are, but the context in which they apply is vague.
I can equally generate examples where the non-blocking behavior you
are a proponent of would break non-blocking UDP apps during a
sendmsg() call when we hit IPSEC resolution. Yet similar language on
blocking semantics exists for sendmsg() in the standards.
The world is shades of gray, implying anything else is foolhardy and
that's how I'm handling this.
> Well, the only reason this doesn't break on a daily basis is because the code
> isn't in the kernel that long and not many people run applications on an
> IPSEC gateway. This will change if kernel based IPSEC is used for roadwarrior
> connections or dnssec based anonymous IPSEC someday. Trust me, you will
> revert this misbehaviour in -stable then.
I use IPSEC every single day in this fashion, and I haven't.
^ permalink raw reply
* Re: sockets affected by IPsec always block (2.6.23)
From: Stefan Rompf @ 2007-12-06 8:49 UTC (permalink / raw)
To: David Miller; +Cc: herbert, simon, linux-kernel, netdev
In-Reply-To: <20071205.182500.166603251.davem@davemloft.net>
Am Donnerstag, 6. Dezember 2007 03:25 schrieb David Miller:
> POSIX says nothing about the semantics of route resolution.
Of course not. Applications must not care about what happens at the transport
layer.
> Non-blocking doesn't mean "cannot sleep no matter what".
... and as O_CREAT on open() isn't specifically documented to apply to
filenames starting with 'a', it is perfectly normal that "echo x >ash" always
fails since 2.6.22. To revert to the old behaviour, please do "echo 1
>/proc/sys/fs/allow_a_file_creation".
Ok, irony aside. Just have a look at
http://www.opengroup.org/onlinepubs/009695399/functions/connect.html (I hope
009695399 is not a personalition cookie ;-)
"If the connection cannot be established immediately and O_NONBLOCK is set for
the file descriptor for the socket, connect() shall fail and set errno to
[EINPROGRESS], but the connection request shall not be aborted, and the
connection shall be established asynchronously."
I think the words "shall fail" and "immediately" are quite clear.
> > If this is changed for some IP sockets, event-driven applications
> > will randomly and subtly break.
>
> If this was such a clear cut case we'd have changed things
> a long time ago, but it isn't so don't pretend this is the
> case.
Well, the only reason this doesn't break on a daily basis is because the code
isn't in the kernel that long and not many people run applications on an
IPSEC gateway. This will change if kernel based IPSEC is used for roadwarrior
connections or dnssec based anonymous IPSEC someday. Trust me, you will
revert this misbehaviour in -stable then.
For some real life applications that break when nonblocking connect() blocks,
please look f.e. at squid or mozilla firefox.
Stefan
^ permalink raw reply
* Re: [PATCH] [IPv4] Reply net unreachable ICMP message
From: Jarek Poplawski @ 2007-12-06 8:47 UTC (permalink / raw)
To: Mitsuru Chinen; +Cc: netdev, David Miller, Rami Rosen
In-Reply-To: <20071206171421.1495c019.mitch@linux.vnet.ibm.com>
On 06-12-2007 09:14, Mitsuru Chinen wrote:
> On Thu, 6 Dec 2007 08:49:47 +0100
> Jarek Poplawski <jarkao2@o2.pl> wrote:
>
>> On 06-12-2007 07:31, Mitsuru Chinen wrote:
>>> IPv4 stack doesn't reply any ICMP destination unreachable message
>>> with net unreachable code when IP detagrams are being discarded
>>> because of no route could be found in the forwarding path.
>>> Incidentally, IPv6 stack replies such ICMPv6 message in the similar
>>> situation.
...
>> This patch seems to be wrong. It overrides err codes from
>> fib_lookup, where such decisions should be made.
>
> fib_lookup() replies -ESRCH in this situation.
> It is necessary to override the variable by the suitable error
> number like the code under e_hostunreach label.
Probably I miss something, but I can't see how can you be sure it's
only -ESRCH possible here? Isn't opt->action() in fib_rules_lookup()
supposed to return this -ENETUNREACH when needed?
Jarek P.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox