* [PATCH 14/14] [ACKVEC]: Remove old infrastructure
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-14-git-send-email-gerrit@erg.abdn.ac.uk>
This removes
* functions for which updates have been provided in the preceding patches and
* the @av_vec_len field - it is no longer necessary since the buffer length is
now always computed dynamically;
* conditional debugging code (CONFIG_IP_DCCP_ACKVEC).
The reason for removing the latter is that Ack Vectors are an almost
inevitable necessity - RFC 4341 says if you use CCID2, Ack Vectors
must be used. Furthermore, the code would be only interesting for going
bug-hunting. Having dealt with several bugs/problems in the code already,
I am positive that the old debugging code is no longer necessary.
Also updated copyrights.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/Kconfig | 3 -
net/dccp/Makefile | 5 +-
net/dccp/ackvec.c | 141 +-----------------------------------------------
net/dccp/ackvec.h | 64 +---------------------
net/dccp/ccids/Kconfig | 1 -
5 files changed, 7 insertions(+), 207 deletions(-)
--- a/net/dccp/Kconfig
+++ b/net/dccp/Kconfig
@@ -25,9 +25,6 @@ config INET_DCCP_DIAG
def_tristate y if (IP_DCCP = y && INET_DIAG = y)
def_tristate m
-config IP_DCCP_ACKVEC
- bool
-
source "net/dccp/ccids/Kconfig"
menu "DCCP Kernel Hacking"
--- a/net/dccp/Makefile
+++ b/net/dccp/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o
-dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
+dccp-y := ccid.o feat.o input.o minisocks.o options.o \
+ output.o proto.o timer.o ackvec.o
dccp_ipv4-y := ipv4.o
@@ -8,8 +9,6 @@ dccp_ipv4-y := ipv4.o
obj-$(subst y,$(CONFIG_IP_DCCP),$(CONFIG_IPV6)) += dccp_ipv6.o
dccp_ipv6-y := ipv6.o
-dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
-
obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -1,26 +1,18 @@
/*
* net/dccp/ackvec.c
*
- * An implementation of the DCCP protocol
+ * An implementation of Ack Vectors for the DCCP protocol
+ * Copyright (c) 2007 University of Aberdeen, Scotland, UK
* Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; version 2 of the License;
*/
-
-#include "ackvec.h"
#include "dccp.h"
-
-#include <linux/dccp.h>
-#include <linux/init.h>
-#include <linux/errno.h>
#include <linux/kernel.h>
-#include <linux/skbuff.h>
#include <linux/slab.h>
-#include <net/sock.h>
-
static struct kmem_cache *dccp_ackvec_slab;
static struct kmem_cache *dccp_ackvec_record_slab;
@@ -31,7 +23,6 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
if (av != NULL) {
av->av_buf_head = av->av_buf_tail = DCCPAV_MAX_ACKVEC_LEN - 1;
av->av_overflow = 0;
- av->av_vec_len = 0;
memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
INIT_LIST_HEAD(&av->av_records);
}
@@ -257,134 +248,6 @@ void dccp_ackvec_input(struct dccp_ackvec *av, u64 seqno, u8 state)
}
}
-/*
- * If several packets are missing, the HC-Receiver may prefer to enter multiple
- * bytes with run length 0, rather than a single byte with a larger run length;
- * this simplifies table updates if one of the missing packets arrives.
- */
-static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
- const unsigned int packets,
- const unsigned char state)
-{
- unsigned int gap;
- long new_head;
-
- if (av->av_vec_len + packets > DCCPAV_MAX_ACKVEC_LEN)
- return -ENOBUFS;
-
- gap = packets - 1;
- new_head = av->av_buf_head - packets;
-
- if (new_head < 0) {
- if (gap > 0) {
- memset(av->av_buf, DCCPAV_NOT_RECEIVED,
- gap + new_head + 1);
- gap = -new_head;
- }
- new_head += DCCPAV_MAX_ACKVEC_LEN;
- }
-
- av->av_buf_head = new_head;
-
- if (gap > 0)
- memset(av->av_buf + av->av_buf_head + 1,
- DCCPAV_NOT_RECEIVED, gap);
-
- av->av_buf[av->av_buf_head] = state;
- av->av_vec_len += packets;
- return 0;
-}
-
-/*
- * Implements the RFC 4340, Appendix A
- */
-int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
- const u64 ackno, const u8 state)
-{
- u8 *cur_head = av->av_buf + av->av_buf_head,
- *buf_end = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
- /*
- * Check at the right places if the buffer is full, if it is, tell the
- * caller to start dropping packets till the HC-Sender acks our ACK
- * vectors, when we will free up space in av_buf.
- *
- * We may well decide to do buffer compression, etc, but for now lets
- * just drop.
- *
- * From Appendix A.1.1 (`New Packets'):
- *
- * Of course, the circular buffer may overflow, either when the
- * HC-Sender is sending data at a very high rate, when the
- * HC-Receiver's acknowledgements are not reaching the HC-Sender,
- * or when the HC-Sender is forgetting to acknowledge those acks
- * (so the HC-Receiver is unable to clean up old state). In this
- * case, the HC-Receiver should either compress the buffer (by
- * increasing run lengths when possible), transfer its state to
- * a larger buffer, or, as a last resort, drop all received
- * packets, without processing them whatsoever, until its buffer
- * shrinks again.
- */
-
- /* See if this is the first ackno being inserted */
- if (av->av_vec_len == 0) {
- *cur_head = state;
- av->av_vec_len = 1;
- } else if (after48(ackno, av->av_buf_ackno)) {
- const u64 delta = dccp_delta_seqno(av->av_buf_ackno, ackno);
-
- /*
- * Look if the state of this packet is the same as the
- * previous ackno and if so if we can bump the head len.
- */
- if (delta == 1 && dccp_ackvec_state(cur_head) == state &&
- dccp_ackvec_runlen(cur_head) < DCCPAV_MAX_RUNLEN)
- *cur_head += 1;
- else if (dccp_ackvec_set_buf_head_state(av, delta, state))
- return -ENOBUFS;
- } else {
- /*
- * A.1.2. Old Packets
- *
- * When a packet with Sequence Number S <= buf_ackno
- * arrives, the HC-Receiver will scan the table for
- * the byte corresponding to S. (Indexing structures
- * could reduce the complexity of this scan.)
- */
- u64 delta = dccp_delta_seqno(ackno, av->av_buf_ackno);
-
- while (1) {
- const u8 len = dccp_ackvec_runlen(cur_head);
- /*
- * valid packets not yet in av_buf have a reserved
- * entry, with a len equal to 0.
- */
- if (*cur_head == DCCPAV_NOT_RECEIVED && delta == 0) {
- dccp_pr_debug("Found %llu reserved seat!\n",
- (unsigned long long)ackno);
- *cur_head = state;
- goto out;
- }
- /* len == 0 means one packet */
- if (delta < len + 1)
- goto out_duplicate;
-
- delta -= len + 1;
- if (++cur_head == buf_end)
- cur_head = av->av_buf;
- }
- }
-
- av->av_buf_ackno = ackno;
-out:
- return 0;
-
-out_duplicate:
- /* Duplicate packet */
- dccp_pr_debug("Received a dup or already considered lost "
- "packet: %llu\n", (unsigned long long)ackno);
- return -EILSEQ;
-}
-
/**
* dccp_ackvec_clear_state - Perform house-keeping / garbage-collection
* This routine is called when the peer acknowledges the receipt of Ack Vectors
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -3,9 +3,9 @@
/*
* net/dccp/ackvec.h
*
- * An implementation of the DCCP protocol
+ * An implementation of Ack Vectors for the DCCP protocol
+ * Copyright (c) 2007 University of Aberdeen, Scotland, UK
* Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@mandriva.com>
- *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -59,7 +59,6 @@ static inline u8 dccp_ackvec_state(const u8 *cell)
* %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
* @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound
* @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
- * @av_veclen: length of the live portion of @av_buf
*/
struct dccp_ackvec {
u8 av_buf[DCCPAV_MAX_ACKVEC_LEN];
@@ -70,7 +69,6 @@ struct dccp_ackvec {
bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
u8 av_overflow:1;
struct list_head av_records;
- u16 av_vec_len;
};
/** struct dccp_ackvec_record - Records information about sent Ack Vectors
@@ -96,19 +94,12 @@ struct dccp_ackvec_record {
u8 avr_ack_nonce:1;
};
-struct sock;
-struct sk_buff;
-
-#ifdef CONFIG_IP_DCCP_ACKVEC
-extern int dccp_ackvec_init(void);
+extern int dccp_ackvec_init(void);
extern void dccp_ackvec_exit(void);
extern struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority);
extern void dccp_ackvec_free(struct dccp_ackvec *av);
-extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
- const u64 ackno, const u8 state);
-
extern void dccp_ackvec_input(struct dccp_ackvec *av, u64 seqno, u8 state);
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
@@ -118,53 +109,4 @@ static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{
return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
}
-#else /* CONFIG_IP_DCCP_ACKVEC */
-static inline int dccp_ackvec_init(void)
-{
- return 0;
-}
-
-static inline void dccp_ackvec_exit(void)
-{
-}
-
-static inline struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
-{
- return NULL;
-}
-
-static inline void dccp_ackvec_free(struct dccp_ackvec *av)
-{
-}
-
-static inline void dccp_ackvec_input(struct dccp_ackvec *av, u64 seq, u8 state)
-{
-
-}
-
-static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
- const u64 ackno, const u8 state)
-{
- return -1;
-}
-
-static inline void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
-{
-}
-
-static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 nonce)
-{
- return -1;
-}
-
-static inline u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
-{
- return 0;
-}
-
-static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
-{
- return true;
-}
-#endif /* CONFIG_IP_DCCP_ACKVEC */
#endif /* _ACKVEC_H */
--- a/net/dccp/ccids/Kconfig
+++ b/net/dccp/ccids/Kconfig
@@ -4,7 +4,6 @@ menu "DCCP CCIDs Configuration (EXPERIMENTAL)"
config IP_DCCP_CCID2
tristate "CCID2 (TCP-Like) (EXPERIMENTAL)"
def_tristate IP_DCCP
- select IP_DCCP_ACKVEC
---help---
CCID 2, TCP-like Congestion Control, denotes Additive Increase,
Multiplicative Decrease (AIMD) congestion control with behavior
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 13/14] [ACKVEC]: Aggregate Ack-Vector related processing into single function
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-13-git-send-email-gerrit@erg.abdn.ac.uk>
This aggregates Ack Vector processing (handling input and clearing old state)
into one function, for the following reasons and benefits:
* duplicated code is removed;
* all Ack Vector-specific processing is now in one place;
* sanity: from an Ack Vector point of view, it is better to clear the old
state first before entering new state;
* Ack Event handling happens mostly within the CCIDs, not the main DCCP module.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/input.c | 38 +++++++++++---------------------------
1 files changed, 11 insertions(+), 27 deletions(-)
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -159,13 +159,16 @@ static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb)
dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
}
-static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
+static void dccp_handle_ackvec_processing(struct sock *sk, struct sk_buff *skb)
{
- struct dccp_sock *dp = dccp_sk(sk);
+ struct dccp_ackvec *av = dccp_sk(sk)->dccps_hc_rx_ackvec;
+ struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
- if (dp->dccps_hc_rx_ackvec != NULL)
- dccp_ackvec_clear_state(dp->dccps_hc_rx_ackvec,
- DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ if (av != NULL) {
+ if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
+ dccp_ackvec_clear_state(av, dcb->dccpd_ack_seq);
+ dccp_ackvec_input(av, dcb->dccpd_seq, DCCPAV_RECEIVED);
+ }
}
static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb)
@@ -364,21 +367,13 @@ discard:
int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
const struct dccp_hdr *dh, const unsigned len)
{
- struct dccp_sock *dp = dccp_sk(sk);
-
if (dccp_check_seqno(sk, skb))
goto discard;
if (dccp_parse_options(sk, NULL, skb))
goto discard;
- if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
- dccp_event_ack_recv(sk, skb);
-
- if (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
- goto discard;
+ dccp_handle_ackvec_processing(sk, skb);
dccp_deliver_input_to_ccids(sk, skb);
return __dccp_rcv_established(sk, skb, dh, len);
@@ -507,11 +502,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
*/
if (dccp_feat_activate_values(sk, &dp->dccps_featneg))
goto unable_to_proceed;
-
- if (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
- goto unable_to_proceed;
+ dccp_handle_ackvec_processing(sk, skb);
dccp_send_ack(sk);
return -1;
@@ -632,14 +623,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (dccp_parse_options(sk, NULL, skb))
goto discard;
- if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ)
- dccp_event_ack_recv(sk, skb);
-
- if (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
- goto discard;
-
+ dccp_handle_ackvec_processing(sk, skb);
dccp_deliver_input_to_ccids(sk, skb);
}
--
1.5.3.GIT
^ permalink raw reply
* [DCCP] [RFC] [Patch 0/14]: Ack Vector implementation + fixes
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev
This set of patches adds functionality to the existing DCCP Ack Vector
implementation, extends it to a full circular buffer, and fixes two
previously undiscovered problems which otherwise result in a corrupted
buffer state.
It is important that Ack Vectors run reliably since otherwise problems in
other parts (in particular CCID2) can not be fixed.
Quite some testing has been performed so that I am almost convinced it is
bug free. To make 100% sure that it contains no further hidden issues
as before, I would like to post this as RFC, to be eventually submitted
next year.
Patch #1: Fixes the problem that CCID2 ignores Ack Vectors on some packets.
Patch #2: Adds a tail pointer to the buffer and makes the size configurable.
Patch #3: Decouples the use of Elapsed Time from the use of Ack Vectors.
Patch #4: Provides inlines for Ack Vector state and run length.
Patch #5: Removes redundancies from the allocation / de-allocation routines.
Patch #6: Splits Ack Vector specific code from option-specific code.
Patch #7: Avoids doing unnecessary work when clearing state: the sender of
Ack Vectors is only interested in the highest-received Ack Number
when clearing state. Hence parsing any Ack Vectors for this purpose
(which only contain lower Ack Numbers) is entirely unnecessary.
Patch #8: Replaces #defines for Ack Vector states with enum.
Patch #9: Provides two extensions required for robustness: overflow handling
(indicated by a flag) and tracking the lowest-unacknowledged sequence
number (tail_ackno)
Patch #10: Inlines for buffer index manipulation, dynamic buffer length calculation.
Patch #11: Implements algorithm to clear buffer state (non-trivial).
Patch #12: Updates the code which registers incoming packets in the buffer.
Patch #13: Aggregates Ack-Vector specific code into one function, thus making it
easier/simpler for the main DCCP module to use Ack Vectors.
Patch #14: Cleans up old and now unused bits.
The above patches have been uploaded to
git://eden-feed.erg.abdn.ac.uk/dccp_exp [dccp]
but please note that the server will be switched off from 21/12 ... 01/08.
Detailed information and documentation can be found on
http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/ack_vectors/
^ permalink raw reply
* [PATCH 11/14] [ACKVEC]: Implement algorithm to update buffer state
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-11-git-send-email-gerrit@erg.abdn.ac.uk>
This implements an algorithm to consistently update the buffer state when
the peer acknowledges receipt of Ack Vectors; updating state in the list of
Ack Vectors as well as in the circular buffer.
The algorithm
* deals with HC-sender acknowledging to HC-receiver and vice versa,
* keeps track of the last unacknowledged but received seqno in tail_ackno,
* has special cases to reset the overflow condition when appropriate,
* is protected against receiving older information (would mess up buffer state).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 82 ++++++++++++++++++++++++++++++++++++++++-------------
1 files changed, 62 insertions(+), 20 deletions(-)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -262,34 +262,76 @@ out_duplicate:
return -EILSEQ;
}
-static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
- struct dccp_ackvec_record *avr)
-{
- struct dccp_ackvec_record *next;
+/**
+ * dccp_ackvec_clear_state - Perform house-keeping / garbage-collection
+ * This routine is called when the peer acknowledges the receipt of Ack Vectors
+ * up to and including @ackno. While based on on section A.3 of RFC 4340, here
+ * are additional precautions to prevent corrupted buffer state. In particular,
+ * we use tail_ackno to identify outdated records; it always marks the earliest
+ * packet of group (2) in 11.4.2.
+ */
+void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
+ {
+ struct dccp_ackvec_record *avr, *next;
+ u8 runlen_now, eff_runlen;
+ s64 delta;
- /* sort out vector length */
- if (av->av_buf_head <= avr->avr_ack_ptr)
- av->av_vec_len = avr->avr_ack_ptr - av->av_buf_head;
- else
- av->av_vec_len = DCCPAV_MAX_ACKVEC_LEN - 1 -
- av->av_buf_head + avr->avr_ack_ptr;
+ avr = dccp_ackvec_lookup(&av->av_records, ackno);
+ if (avr == NULL)
+ return;
+ /*
+ * Deal with outdated acknowledgments: this arises when e.g. there are
+ * several old records and the acks from the peer come in slowly. In
+ * that case we may still have records that pre-date tail_ackno.
+ */
+ delta = dccp_delta_seqno(av->av_tail_ackno, avr->avr_ack_ackno);
+ if (delta < 0)
+ goto free_records;
+ /*
+ * Deal with overlapping Ack Vectors: don't subtract more than the
+ * number of packets between tail_ackno and ack_ackno.
+ */
+ eff_runlen = delta < avr->avr_ack_runlen ? delta : avr->avr_ack_runlen;
- /* free records */
+ runlen_now = dccp_ackvec_runlen(av->av_buf + avr->avr_ack_ptr);
+ /*
+ * The run length of Ack Vector cells does not decrease over time. If
+ * the run length is the same as at the time the Ack Vector was sent, we
+ * free the ack_ptr cell. That cell can however not be freed if the run
+ * length has increased: in this case we need to move the tail pointer
+ * backwards (towards higher indices), to its next-oldest neighbour.
+ */
+ if (runlen_now > eff_runlen) {
+
+ av->av_buf[avr->avr_ack_ptr] -= eff_runlen + 1;
+ av->av_buf_tail = dccp_ackvec_idx_add(avr->avr_ack_ptr, 1);
+
+ /* This move may not have cleared the overflow flag. */
+ if (av->av_overflow)
+ av->av_overflow = (av->av_buf_head == av->av_buf_tail);
+ } else {
+ av->av_buf_tail = avr->avr_ack_ptr;
+ /*
+ * We have made sure that avr points to a valid cell within the
+ * buffer. This cell is either older than head, or equals head
+ * (empty buffer): in both cases we no longer have any overflow.
+ */
+ av->av_overflow = 0;
+ }
+
+ /*
+ * The peer has acknowledged up to and including ack_ackno. Hence the
+ * first packet in group (2) of 11.4.2 is the successor of ack_ackno.
+ */
+ av->av_tail_ackno = ADD48(avr->avr_ack_ackno, 1);
+
+free_records:
list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) {
list_del(&avr->avr_node);
kmem_cache_free(dccp_ackvec_record_slab, avr);
}
}
-void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
-{
- struct dccp_ackvec_record *avr;
-
- avr = dccp_ackvec_lookup(&av->av_records, ackno);
- if (avr != NULL)
- dccp_ackvec_throw_record(av, avr);
-}
-
int __init dccp_ackvec_init(void)
{
dccp_ackvec_slab = kmem_cache_create("dccp_ackvec",
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 01/14] [CCID2]: Ack Vectors can happen on most packets
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-1-git-send-email-gerrit@erg.abdn.ac.uk>
CCID2 feedback only considers Ack/DataAck packets, but Ack Vectors can appear
on other packets, too. In RFC 4340, 11.4 the only restriction is that they must
not appear on Data or Request packets.
A possible case is for instance a Sync packet used for feature-negotiation
(as used e.g in section 6.6.1 of RFC 4340). In this case the host must answer
with a SyncAck (7.5.4). Now, if the Sync packet carried an Ack Vector then
the SyncAck acknowledges the receipt of that Ack Vector (thus changing the
Acknowledgment Window, cf. 11.4.2); but the current code would not allow to
parse the received Ack Vector.
The fix is in parsing Ack Vectors on all packet types which are allowed to
carry an Ack Vector.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ccids/ccid2.c | 7 +------
1 files changed, 1 insertions(+), 6 deletions(-)
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -549,13 +549,8 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
if (hctx->ccid2hctx_seqh == hctx->ccid2hctx_seqt)
return;
- switch (DCCP_SKB_CB(skb)->dccpd_type) {
- case DCCP_PKT_ACK:
- case DCCP_PKT_DATAACK:
- break;
- default:
+ if (dccp_packet_without_ack(skb))
return;
- }
ackno = DCCP_SKB_CB(skb)->dccpd_ack_seq;
if (after48(ackno, hctx->ccid2hctx_high_ack))
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 03/14] [ACKVEC]: Use Elapsed Time separately
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-3-git-send-email-gerrit@erg.abdn.ac.uk>
This decouples the use of Elapsed Time options from the use of Ack Vectors, so
that Elapsed Time options are no longer added automatically to each Ack Vector.
There are three reasons for this:
1. The Elapsed Time information is nowhere used in the code.
2. DCCP does not implement rate-based pacing of acknowledgments. The only
recommendation for always including Elapsed Time is in section 11.3 of
RFC 4340: "Receivers that rate-pace acknowledgements SHOULD [...]
include Elapsed Time options". But such is not the case here.
3. It does not really improve estimation accuracy. The Elapsed Time field only
records the time between the arrival of the last acknowledgeable packet and
the time the Ack Vector is sent out. Since Linux does not (yet) implement
delayed Acks, the time difference will typically be small, since often the
arrival of a data packet triggers sending feedback at the HC-receiver.
If the Ack Vector has a wide coverage (up to 16192) then the Elapsed Time is
not very meaningful for older packets.
If indeed elapsed time is required by the endpoint or CCID, then using
Timestamp options can provide the same information (elapsed time field
in the Timestamp Echo option).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 11 -----------
net/dccp/ackvec.h | 3 ---
2 files changed, 0 insertions(+), 14 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -12,7 +12,6 @@
*/
#include <linux/compiler.h>
-#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/types.h>
@@ -46,7 +45,6 @@
* @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to
* %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
* @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
- * @av_time: the time in usecs
* @av_veclen: length of the live portion of @av_buf
*/
struct dccp_ackvec {
@@ -56,7 +54,6 @@ struct dccp_ackvec {
u64 av_buf_ackno:48;
bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
struct list_head av_records;
- ktime_t av_time;
u16 av_vec_len;
};
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -71,18 +71,9 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
u16 len = av->av_vec_len + 2 * nr_opts;
u8 i, nonce = 0;
- u32 elapsed_time;
const unsigned char *tail, *from;
unsigned char *to;
struct dccp_ackvec_record *avr;
- suseconds_t delta;
-
- delta = ktime_us_delta(ktime_get_real(), av->av_time);
- elapsed_time = delta / 10;
-
- if (elapsed_time != 0 &&
- dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
- return -1;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
/*
@@ -162,7 +153,6 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
if (av != NULL) {
av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1;
- av->av_time = ktime_set(0, 0);
av->av_vec_len = 0;
memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
INIT_LIST_HEAD(&av->av_records);
@@ -321,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
}
av->av_buf_ackno = ackno;
- av->av_time = ktime_get_real();
out:
return 0;
^ permalink raw reply
* [PATCH 12/14] [ACKVEC]: Update Ack Vector input routine
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-12-git-send-email-gerrit@erg.abdn.ac.uk>
This patch updates the code which registers new packets as received, using the
new circular buffer interface, it now
* supports both tail/head pointers and buffer wrap-around,
* deals with overflow (head/tail move in lock-step), and
* uses dynamic buffer-length computation.
The updated code is also partioned differently, into
1. dealing with the empty buffer,
2. adding new packets into non-empty buffer,
3. reserving space when encountering a `hole' in the sequence space,
4. updating old state and deciding when old state is irrelevant.
Much of the old code and naming is reused.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++
net/dccp/ackvec.h | 6 +++
2 files changed, 129 insertions(+), 0 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -109,6 +109,7 @@ extern void dccp_ackvec_free(struct dccp_ackvec *av);
extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
const u64 ackno, const u8 state);
+extern void dccp_ackvec_input(struct dccp_ackvec *av, u64 seqno, u8 state);
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
@@ -136,6 +137,11 @@ static inline void dccp_ackvec_free(struct dccp_ackvec *av)
{
}
+static inline void dccp_ackvec_input(struct dccp_ackvec *av, u64 seq, u8 state)
+{
+
+}
+
static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
const u64 ackno, const u8 state)
{
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -134,6 +134,129 @@ u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
return dccp_ackvec_idx_sub(av->av_buf_tail, av->av_buf_head);
}
+/* Mark @num entries after buf_head as "Not yet received". */
+static void dccp_ackvec_reserve_seats(struct dccp_ackvec *av, u16 num)
+{
+ u16 start = dccp_ackvec_idx_add(av->av_buf_head, 1),
+ len = DCCPAV_MAX_ACKVEC_LEN - start;
+
+ /* check for buffer wrap-around */
+ if (num > len) {
+ memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, len);
+ start = 0;
+ num -= len;
+ }
+ if (num)
+ memset(av->av_buf + start, DCCPAV_NOT_RECEIVED, num);
+}
+
+/**
+ * dccp_ackvec_update_old - Update previous state as per RFC 4340, 11.4.1
+ * @av: non-empty buffer to update
+ * @distance: negative or zero distance of @seqno from buf_ackno downward
+ * @seqno: the (old) sequence number whose record is to be updated
+ * @state: state in which packet carrying @seqno was received
+ */
+static void dccp_ackvec_update_old(struct dccp_ackvec *av, s64 distance,
+ u64 seqno, enum dccp_ackvec_states state)
+{
+ u16 ptr = av->av_buf_head;
+
+ BUG_ON(distance > 0);
+ if (unlikely(dccp_ackvec_is_empty(av)))
+ return;
+
+ do {
+ u8 runlen = dccp_ackvec_runlen(av->av_buf + ptr);
+
+ if (distance + runlen >= 0) {
+ /*
+ * Only update the state if packet has not been received
+ * yet. This is OK as per the second table in RFC 4340,
+ * 11.4.1; i.e. here we are using the following table:
+ * RECEIVED
+ * 0 1 3
+ * S +---+---+---+
+ * T 0 | 0 | 0 | 0 |
+ * O +---+---+---+
+ * R 1 | 1 | 1 | 1 |
+ * E +---+---+---+
+ * D 3 | 0 | 1 | 3 |
+ * +---+---+---+
+ * The "Not Received" state was set by reserve_seats().
+ */
+ if (av->av_buf[ptr] == DCCPAV_NOT_RECEIVED)
+ av->av_buf[ptr] = state;
+ else
+ dccp_pr_debug("Not changing %llu state to %u\n",
+ (unsigned long long)seqno, state);
+ break;
+ }
+
+ distance += runlen + 1;
+ ptr = dccp_ackvec_idx_add(ptr, 1);
+
+ } while (ptr != av->av_buf_tail);
+}
+
+/**
+ * dccp_ackvec_add_new - Record one or more new entries in Ack Vector buffer
+ * @av: container of buffer to update (can be empty or non-empty)
+ * @num_packets: number of packets to register (must be >= 1)
+ * @seqno: sequence number of the first packet in @num_packets
+ * @state: state in which packet carrying @seqno was received
+ */
+static void dccp_ackvec_add_new(struct dccp_ackvec *av, u16 num_packets,
+ u64 seqno, enum dccp_ackvec_states state)
+{
+ if ((num_packets + dccp_ackvec_buflen(av)) >= DCCPAV_MAX_ACKVEC_LEN) {
+ DCCP_CRIT("Ack Vector buffer overflow: dropping old entries\n");
+ av->av_overflow = true;
+ }
+
+ av->av_buf_head = dccp_ackvec_idx_sub(av->av_buf_head, num_packets);
+ if (av->av_overflow)
+ av->av_buf_tail = av->av_buf_head;
+
+ av->av_buf[av->av_buf_head] = state;
+ av->av_buf_ackno = seqno;
+
+ if (num_packets > 1)
+ dccp_ackvec_reserve_seats(av, num_packets - 1);
+}
+
+/**
+ * dccp_ackvec_input - Register incoming packet in the buffer
+ * @av: buffer/records to update
+ * @seqno: sequence number to register as received
+ * @state: how packet with @seqno was received, one of %dccp_ackvec_states
+ */
+void dccp_ackvec_input(struct dccp_ackvec *av, u64 seqno, u8 state)
+{
+ if (dccp_ackvec_is_empty(av)) {
+
+ dccp_ackvec_add_new(av, 1, seqno, state);
+ av->av_tail_ackno = seqno;
+
+ } else {
+ s64 num_packets = dccp_delta_seqno(av->av_buf_ackno, seqno);
+ u8 *current_head = av->av_buf + av->av_buf_head;
+
+ if (num_packets == 1 &&
+ dccp_ackvec_state(current_head) == state &&
+ dccp_ackvec_runlen(current_head) < DCCPAV_MAX_RUNLEN) {
+
+ *current_head += 1;
+ av->av_buf_ackno = seqno;
+
+ } else if (num_packets > 0) {
+ dccp_ackvec_add_new(av, num_packets, seqno, state);
+ } else {
+ dccp_ackvec_update_old(av, num_packets, seqno, state);
+ }
+ }
+}
+
/*
* If several packets are missing, the HC-Receiver may prefer to enter multiple
* bytes with run length 0, rather than a single byte with a larger run length;
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 10/14] [ACKVEC]: Determine buffer length dynamically
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-10-git-send-email-gerrit@erg.abdn.ac.uk>
The length of the circular Ack Vector buffer is now determined dynamically,
as the span between head to tail.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 21 +++++++++++++++++++++
net/dccp/ackvec.h | 7 +++++++
net/dccp/options.c | 7 ++++---
3 files changed, 32 insertions(+), 3 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -22,6 +22,7 @@
* the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1
* will be sufficient for most cases of low Ack Ratios, using a value of 2 gives
* more headroom if Ack Ratio is higher or when the sender acknowledges slowly.
+ * The maximum value is bounded by the u16 types for indices and functions.
*/
#define DCCPAV_NUM_ACKVECS 2
#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS)
@@ -110,6 +111,7 @@ extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
+extern u16 dccp_ackvec_buflen(const struct dccp_ackvec *av);
static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{
@@ -149,6 +151,11 @@ static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8
return -1;
}
+static inline u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
+{
+ return 0;
+}
+
static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{
return true;
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -114,6 +114,27 @@ static struct dccp_ackvec_record *dccp_ackvec_lookup(struct list_head *av_list,
}
/*
+ * Buffer index and length computation using modulo-buffersize arithmetic.
+ * Note that, as pointers move from right to left, head is `before' tail.
+ */
+static inline u16 dccp_ackvec_idx_add(const u16 a, const u16 b)
+{
+ return (a + b) % DCCPAV_MAX_ACKVEC_LEN;
+}
+
+static inline u16 dccp_ackvec_idx_sub(const u16 a, const u16 b)
+{
+ return dccp_ackvec_idx_add(a, DCCPAV_MAX_ACKVEC_LEN - b);
+}
+
+u16 dccp_ackvec_buflen(const struct dccp_ackvec *av)
+{
+ if (unlikely(av->av_overflow))
+ return DCCPAV_MAX_ACKVEC_LEN;
+ return dccp_ackvec_idx_sub(av->av_buf_tail, av->av_buf_head);
+}
+
+/*
* If several packets are missing, the HC-Receiver may prefer to enter multiple
* bytes with run length 0, rather than a single byte with a larger run length;
* this simplifies table updates if one of the missing packets arrives.
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -432,9 +432,10 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
{
struct dccp_ackvec *av = dccp_sk(sk)->dccps_hc_rx_ackvec;
+ const u16 buflen = dccp_ackvec_buflen(av);
/* Figure out how many options do we need to represent the ackvec */
- const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
- u16 len = av->av_vec_len + 2 * nr_opts;
+ const u16 nr_opts = DIV_ROUND_UP(buflen, DCCP_SINGLE_OPT_MAXLEN);
+ u16 len = buflen + 2 * nr_opts;
u8 i, nonce = 0;
const unsigned char *tail, *from;
unsigned char *to;
@@ -451,7 +452,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
DCCP_SKB_CB(skb)->dccpd_opt_len += len;
to = skb_push(skb, len);
- len = av->av_vec_len;
+ len = buflen;
from = av->av_buf + av->av_buf_head;
tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 08/14] [ACKVEC]: Use enum to enumerate Ack Vector states
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-8-git-send-email-gerrit@erg.abdn.ac.uk>
This replaces 3 #defines with an enum containing all possible
Ack Vector states as per RFC 4340, 11.4. This helps to reduce
the length of several expressions.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 7 +++----
net/dccp/ackvec.h | 10 ++++++----
net/dccp/ccids/ccid2.c | 7 +++----
net/dccp/input.c | 9 +++------
4 files changed, 15 insertions(+), 18 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -26,10 +26,12 @@
#define DCCPAV_NUM_ACKVECS 2
#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS)
-#define DCCP_ACKVEC_STATE_RECEIVED 0
-#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6)
-#define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6)
-
+enum dccp_ackvec_states {
+ DCCPAV_RECEIVED = 0x00,
+ DCCPAV_ECN_MARKED = 0x40,
+ DCCPAV_RESERVED = 0x80,
+ DCCPAV_NOT_RECEIVED = 0xC0
+};
#define DCCPAV_MAX_RUNLEN 0x3F
static inline u8 dccp_ackvec_runlen(const u8 *cell)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -124,7 +124,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
if (new_head < 0) {
if (gap > 0) {
- memset(av->av_buf, DCCP_ACKVEC_STATE_NOT_RECEIVED,
+ memset(av->av_buf, DCCPAV_NOT_RECEIVED,
gap + new_head + 1);
gap = -new_head;
}
@@ -135,7 +135,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
if (gap > 0)
memset(av->av_buf + av->av_buf_head + 1,
- DCCP_ACKVEC_STATE_NOT_RECEIVED, gap);
+ DCCPAV_NOT_RECEIVED, gap);
av->av_buf[av->av_buf_head] = state;
av->av_vec_len += packets;
@@ -205,8 +205,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
* valid packets not yet in av_buf have a reserved
* entry, with a len equal to 0.
*/
- if (*cur_head == DCCP_ACKVEC_STATE_NOT_RECEIVED &&
- delta == 0) {
+ if (*cur_head == DCCPAV_NOT_RECEIVED && delta == 0) {
dccp_pr_debug("Found %llu reserved seat!\n",
(unsigned long long)ackno);
*cur_head = state;
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -605,13 +605,12 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
const u8 state = dccp_ackvec_state(vector);
/* new packet received or marked */
- if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+ if (state != DCCPAV_NOT_RECEIVED &&
!seqp->ccid2s_acked) {
- if (state ==
- DCCP_ACKVEC_STATE_ECN_MARKED) {
+ if (state == DCCPAV_ECN_MARKED)
ccid2_congestion_event(sk,
seqp);
- } else
+ else
ccid2_new_ack(sk, seqp,
&maxincr);
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -377,8 +377,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq,
- DCCP_ACKVEC_STATE_RECEIVED))
+ DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
goto discard;
dccp_deliver_input_to_ccids(sk, skb);
@@ -511,8 +510,7 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk,
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq,
- DCCP_ACKVEC_STATE_RECEIVED))
+ DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
goto unable_to_proceed;
dccp_send_ack(sk);
@@ -639,8 +637,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (dp->dccps_hc_rx_ackvec != NULL &&
dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_seq,
- DCCP_ACKVEC_STATE_RECEIVED))
+ DCCP_SKB_CB(skb)->dccpd_seq, DCCPAV_RECEIVED))
goto discard;
dccp_deliver_input_to_ccids(sk, skb);
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 05/14] [ACKVEC]: Smaller allocation/deallocation routines
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-5-git-send-email-gerrit@erg.abdn.ac.uk>
This patch removes redundant bits, implementing the same functionality with less code.
The details are:
* The INIT_LIST_HEAD in dccp_ackvec_record_new was redundant, since the list pointers
were later overwritten when the node was added via list_add().
* dccp_ackvec_record_new() was called only in one instance in the entire ackvec code.
* The calls to list_del_init() before calling dccp_ackvec_record_delete() were redundant,
since subsequently the entire element was freed anyway.
* Similarly, since all calls to dccp_ackvec_record_delete() were preceded to a call to
list_del_init(), the WARN_ON test would never evaluate to true.
* Also, since all calls to dccp_ackvec_record_delete() were made from within list_for
each_entry_safe(), the test for avr == NULL was redundant.
* The list_empty() test in ackvec_free was redundant, since the same condition is
embedded in the loop condition of the subsequent list_for_each_entry_safe().
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 78 +++++++++++++++++++----------------------------------
1 files changed, 28 insertions(+), 50 deletions(-)
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -24,24 +24,34 @@
static struct kmem_cache *dccp_ackvec_slab;
static struct kmem_cache *dccp_ackvec_record_slab;
-static struct dccp_ackvec_record *dccp_ackvec_record_new(void)
+struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
{
- struct dccp_ackvec_record *avr =
- kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
+ struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
+
+ if (av != NULL) {
+ av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1;
+ av->av_vec_len = 0;
+ memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
+ INIT_LIST_HEAD(&av->av_records);
+ }
+ return av;
+}
- if (avr != NULL)
- INIT_LIST_HEAD(&avr->avr_node);
+static void dccp_ackvec_purge_records(struct dccp_ackvec *av)
+{
+ struct dccp_ackvec_record *cur, *next;
- return avr;
+ list_for_each_entry_safe(cur, next, &av->av_records, avr_node)
+ kmem_cache_free(dccp_ackvec_record_slab, cur);
+ INIT_LIST_HEAD(&av->av_records);
}
-static void dccp_ackvec_record_delete(struct dccp_ackvec_record *avr)
+void dccp_ackvec_free(struct dccp_ackvec *av)
{
- if (unlikely(avr == NULL))
- return;
- /* Check if deleting a linked record */
- WARN_ON(!list_empty(&avr->avr_node));
- kmem_cache_free(dccp_ackvec_record_slab, avr);
+ if (likely(av != NULL)) {
+ dccp_ackvec_purge_records(av);
+ kmem_cache_free(dccp_ackvec_slab, av);
+ }
}
static void dccp_ackvec_insert_avr(struct dccp_ackvec *av,
@@ -85,7 +95,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
return -1;
}
- avr = dccp_ackvec_record_new();
+ avr = kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
if (avr == NULL)
return -1;
@@ -147,37 +157,6 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
return 0;
}
-struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
-{
- struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
-
- if (av != NULL) {
- av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1;
- av->av_vec_len = 0;
- memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
- INIT_LIST_HEAD(&av->av_records);
- }
-
- return av;
-}
-
-void dccp_ackvec_free(struct dccp_ackvec *av)
-{
- if (unlikely(av == NULL))
- return;
-
- if (!list_empty(&av->av_records)) {
- struct dccp_ackvec_record *avr, *next;
-
- list_for_each_entry_safe(avr, next, &av->av_records, avr_node) {
- list_del_init(&avr->avr_node);
- dccp_ackvec_record_delete(avr);
- }
- }
-
- kmem_cache_free(dccp_ackvec_slab, av);
-}
-
/*
* If several packets are missing, the HC-Receiver may prefer to enter multiple
* bytes with run length 0, rather than a single byte with a larger run length;
@@ -321,8 +300,8 @@ static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
/* free records */
list_for_each_entry_safe_from(avr, next, &av->av_records, avr_node) {
- list_del_init(&avr->avr_node);
- dccp_ackvec_record_delete(avr);
+ list_del(&avr->avr_node);
+ kmem_cache_free(dccp_ackvec_record_slab, avr);
}
}
@@ -431,10 +410,9 @@ int __init dccp_ackvec_init(void)
if (dccp_ackvec_slab == NULL)
goto out_err;
- dccp_ackvec_record_slab =
- kmem_cache_create("dccp_ackvec_record",
- sizeof(struct dccp_ackvec_record),
- 0, SLAB_HWCACHE_ALIGN, NULL);
+ dccp_ackvec_record_slab = kmem_cache_create("dccp_ackvec_record",
+ sizeof(struct dccp_ackvec_record),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
if (dccp_ackvec_record_slab == NULL)
goto out_destroy_slab;
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 09/14] [ACKVEC]: Support for circular Ack Vector buffer with overflow handling
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-9-git-send-email-gerrit@erg.abdn.ac.uk>
This adds missing bits to complete the implementation of a circular buffer for
Ack Vector information, with the following changes:
(a) An `overflow' flag to deal with the case of overflow. As before, dynamic
growth of the buffer will not be supported; but code will be added to deal
more gracefully with overflowing Ack Vector buffers (if that ever happens).
(b) A `tail_seqno' field. When naively implementing the algorithm of Appendix A
in RFC 4340, problems arise whenever subsequent Ack Vector records overlap,
which can bring the entire run length calculation completely out of synch.
(This is documented on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/\
ack_vectors/tracking_tail_ackno/ .)
This further allowed to simplify dccp_ackvec_pending() - the #ifdef is no longer
necessary since buf_empty is always true when IP_DCCP_ACKVEC is not configured.
Note on overflow handling:
-------------------------
The Ack Vector code previously simply started to drop packets when the
Ack Vector buffer overflowed. This means that the userspace application
will not be able to get its data, only because of an Ack Vector problem.
Furthermore, overflow may be transient, so that the application later
recovers from the overflow. Recovering from lost packets is more difficult
(e.g. video key frames).
Hence the patch uses a different policy: when the buffer overflows, the oldest
entries are subsequently overwritten. This has a higher chance of recovery.
Details are on http://www.erg.abdn.ac.uk/users/gerrit/dccp/notes/ack_vectors/
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 11 ++++++++++-
net/dccp/ackvec.h | 12 ++++++++----
net/dccp/dccp.h | 14 +++++++-------
net/dccp/options.c | 5 ++---
4 files changed, 27 insertions(+), 15 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -53,8 +53,10 @@ static inline u8 dccp_ackvec_state(const u8 *cell)
* @av_buf_head: head index; begin of live portion in @av_buf
* @av_buf_tail: tail index; first index _after_ the live portion in @av_buf
* @av_buf_ackno: highest seqno of acknowledgeable packet recorded in @av_buf
+ * @av_tail_ackno: lowest seqno of acknowledgeable packet recorded in @av_buf
* @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to
* %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
+ * @av_overflow: if 1 then buf_head == buf_tail indicates buffer wraparound
* @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
* @av_veclen: length of the live portion of @av_buf
*/
@@ -63,7 +65,9 @@ struct dccp_ackvec {
u16 av_buf_head;
u16 av_buf_tail;
u64 av_buf_ackno:48;
+ u64 av_tail_ackno:48;
bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
+ u8 av_overflow:1;
struct list_head av_records;
u16 av_vec_len;
};
@@ -107,9 +111,9 @@ extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
-static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
+static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{
- return av->av_vec_len;
+ return av->av_overflow == 0 && av->av_buf_head == av->av_buf_tail;
}
#else /* CONFIG_IP_DCCP_ACKVEC */
static inline int dccp_ackvec_init(void)
@@ -145,9 +149,9 @@ static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8
return -1;
}
-static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
+static inline bool dccp_ackvec_is_empty(const struct dccp_ackvec *av)
{
- return 0;
+ return true;
}
#endif /* CONFIG_IP_DCCP_ACKVEC */
#endif /* _ACKVEC_H */
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -29,7 +29,8 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
if (av != NULL) {
- av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1;
+ av->av_buf_head = av->av_buf_tail = DCCPAV_MAX_ACKVEC_LEN - 1;
+ av->av_overflow = 0;
av->av_vec_len = 0;
memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
INIT_LIST_HEAD(&av->av_records);
@@ -74,6 +75,14 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
avr->avr_ack_nonce = nonce_sum;
avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head);
/*
+ * When the buffer overflows, we keep no more than one record. This is
+ * the simplest way of disambiguating sender-Acks dating from before the
+ * overflow from sender-Acks which refer to after the overflow; a simple
+ * solution is preferable here since we are handling an exception.
+ */
+ if (av->av_overflow)
+ dccp_ackvec_purge_records(av);
+ /*
* Since GSS is incremented for each packet, the list is automatically
* arranged in descending order of @ack_seqno.
*/
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -410,15 +410,15 @@ static inline void dccp_schedule_ack(struct sock *sk)
inet_csk_schedule_ack(sk);
}
+static inline int dccp_ackvec_pending(const struct sock *sk)
+{
+ return dccp_sk(sk)->dccps_hc_rx_ackvec != NULL &&
+ !dccp_ackvec_is_empty(dccp_sk(sk)->dccps_hc_rx_ackvec);
+}
+
static inline int dccp_ack_pending(const struct sock *sk)
{
- const struct dccp_sock *dp = dccp_sk(sk);
- return
-#ifdef CONFIG_IP_DCCP_ACKVEC
- (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) ||
-#endif
- inet_csk_ack_scheduled(sk);
+ return dccp_ackvec_pending(sk) || inet_csk_ack_scheduled(sk);
}
extern int dccp_feat_signal_nn_change(struct sock *sk, u8 feat, u64 nn_val);
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -589,9 +589,8 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
if (dccp_insert_option_timestamp(sk, skb))
return -1;
- } else if (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
- dccp_insert_option_ackvec(sk, skb) ) {
+ } else if (dccp_ackvec_pending(sk) &&
+ dccp_insert_option_ackvec(sk, skb)) {
return -1;
}
}
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 04/14] [ACKVEC]: Inlines for run length and state
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-4-git-send-email-gerrit@erg.abdn.ac.uk>
This provides inlines for Ack Vector run length and state, which allow to wrap
several instances of the same code into function calls.
The unused function dccp_ackvec_print() (which also relied on the older
constants), has been removed.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 71 +++++++++++-------------------------------------
net/dccp/ackvec.h | 13 +++++++-
net/dccp/ccids/ccid2.c | 7 ++---
3 files changed, 30 insertions(+), 61 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -30,8 +30,17 @@
#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6)
#define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6)
-#define DCCP_ACKVEC_STATE_MASK 0xC0 /* 11000000 */
-#define DCCP_ACKVEC_LEN_MASK 0x3F /* 00111111 */
+#define DCCPAV_MAX_RUNLEN 0x3F
+
+static inline u8 dccp_ackvec_runlen(const u8 *cell)
+{
+ return *cell & DCCPAV_MAX_RUNLEN;
+}
+
+static inline u8 dccp_ackvec_state(const u8 *cell)
+{
+ return *cell & ~DCCPAV_MAX_RUNLEN;
+}
/** struct dccp_ackvec - Ack Vector main data structure
*
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -135,7 +135,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
avr->avr_ack_ptr = av->av_buf_head;
avr->avr_ack_ackno = av->av_buf_ackno;
avr->avr_ack_nonce = nonce;
- avr->avr_ack_runlen = av->av_buf[av->av_buf_head] & DCCP_ACKVEC_LEN_MASK;
+ avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head);
dccp_ackvec_insert_avr(av, avr);
@@ -178,18 +178,6 @@ void dccp_ackvec_free(struct dccp_ackvec *av)
kmem_cache_free(dccp_ackvec_slab, av);
}
-static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av,
- const u32 index)
-{
- return av->av_buf[index] & DCCP_ACKVEC_STATE_MASK;
-}
-
-static inline u8 dccp_ackvec_len(const struct dccp_ackvec *av,
- const u32 index)
-{
- return av->av_buf[index] & DCCP_ACKVEC_LEN_MASK;
-}
-
/*
* If several packets are missing, the HC-Receiver may prefer to enter multiple
* bytes with run length 0, rather than a single byte with a larger run length;
@@ -234,6 +222,8 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
const u64 ackno, const u8 state)
{
+ u8 *cur_head = av->av_buf + av->av_buf_head,
+ *buf_end = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
/*
* Check at the right places if the buffer is full, if it is, tell the
* caller to start dropping packets till the HC-Sender acks our ACK
@@ -258,7 +248,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
/* See if this is the first ackno being inserted */
if (av->av_vec_len == 0) {
- av->av_buf[av->av_buf_head] = state;
+ *cur_head = state;
av->av_vec_len = 1;
} else if (after48(ackno, av->av_buf_ackno)) {
const u64 delta = dccp_delta_seqno(av->av_buf_ackno, ackno);
@@ -267,10 +257,9 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
* Look if the state of this packet is the same as the
* previous ackno and if so if we can bump the head len.
*/
- if (delta == 1 &&
- dccp_ackvec_state(av, av->av_buf_head) == state &&
- dccp_ackvec_len(av, av->av_buf_head) < DCCP_ACKVEC_LEN_MASK)
- av->av_buf[av->av_buf_head]++;
+ if (delta == 1 && dccp_ackvec_state(cur_head) == state &&
+ dccp_ackvec_runlen(cur_head) < DCCPAV_MAX_RUNLEN)
+ *cur_head += 1;
else if (dccp_ackvec_set_buf_head_state(av, delta, state))
return -ENOBUFS;
} else {
@@ -283,21 +272,18 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
* could reduce the complexity of this scan.)
*/
u64 delta = dccp_delta_seqno(ackno, av->av_buf_ackno);
- u32 index = av->av_buf_head;
while (1) {
- const u8 len = dccp_ackvec_len(av, index);
- const u8 state = dccp_ackvec_state(av, index);
+ const u8 len = dccp_ackvec_runlen(cur_head);
/*
* valid packets not yet in av_buf have a reserved
* entry, with a len equal to 0.
*/
- if (state == DCCP_ACKVEC_STATE_NOT_RECEIVED &&
- len == 0 && delta == 0) { /* Found our
- reserved seat! */
+ if (*cur_head == DCCP_ACKVEC_STATE_NOT_RECEIVED &&
+ delta == 0) {
dccp_pr_debug("Found %llu reserved seat!\n",
(unsigned long long)ackno);
- av->av_buf[index] = state;
+ *cur_head = state;
goto out;
}
/* len == 0 means one packet */
@@ -305,8 +291,8 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
goto out_duplicate;
delta -= len + 1;
- if (++index == DCCPAV_MAX_ACKVEC_LEN)
- index = 0;
+ if (++cur_head == buf_end)
+ cur_head = av->av_buf;
}
}
@@ -321,31 +307,6 @@ out_duplicate:
return -EILSEQ;
}
-#ifdef CONFIG_IP_DCCP_DEBUG
-void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len)
-{
- dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len,
- (unsigned long long)ackno);
-
- while (len--) {
- const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6;
- const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
-
- dccp_pr_debug_cat("%d,%d|", state, rl);
- ++vector;
- }
-
- dccp_pr_debug_cat("\n");
-}
-
-void dccp_ackvec_print(const struct dccp_ackvec *av)
-{
- dccp_ackvector_print(av->av_buf_ackno,
- av->av_buf + av->av_buf_head,
- av->av_vec_len);
-}
-#endif
-
static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
struct dccp_ackvec_record *avr)
{
@@ -409,7 +370,7 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
*/
avr = list_entry(av->av_records.next, struct dccp_ackvec_record, avr_node);
while (i--) {
- const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
+ const u8 rl = dccp_ackvec_runlen(vector);
u64 ackno_end_rl;
dccp_set_seqno(&ackno_end_rl, *ackno - rl);
@@ -426,8 +387,8 @@ static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
break;
found:
if (between48(avr->avr_ack_seqno, ackno_end_rl, *ackno)) {
- const u8 state = *vector & DCCP_ACKVEC_STATE_MASK;
- if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) {
+ if (dccp_ackvec_state(vector) !=
+ DCCP_ACKVEC_STATE_NOT_RECEIVED) {
dccp_pr_debug("%s ACK vector 0, len=%d, "
"ack_seqno=%llu, ack_ackno=%llu, "
"ACKED!\n",
--- a/net/dccp/ccids/ccid2.c
+++ b/net/dccp/ccids/ccid2.c
@@ -578,8 +578,8 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
&vector, &veclen)) != -1) {
/* go through this ack vector */
while (veclen--) {
- const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK;
- u64 ackno_end_rl = SUB48(ackno, rl);
+ u64 ackno_end_rl = SUB48(ackno,
+ dccp_ackvec_runlen(vector));
ccid2_pr_debug("ackvec start:%llu end:%llu\n",
(unsigned long long)ackno,
@@ -602,8 +602,7 @@ static void ccid2_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
* run length
*/
while (between48(seqp->ccid2s_seq,ackno_end_rl,ackno)) {
- const u8 state = *vector &
- DCCP_ACKVEC_STATE_MASK;
+ const u8 state = dccp_ackvec_state(vector);
/* new packet received or marked */
if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED &&
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 06/14] [ACKVEC]: Simplify adding Ack Vector records, split option-specific code
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-6-git-send-email-gerrit@erg.abdn.ac.uk>
This patch
* simplifies the dccp_ackvec_insert_avr() routine: the BUG_ON was redundant,
since the list is automatically arranged in descending order of ack_no;
* separates Ack Vector housekeeping code from option-specific code;
* shifts option-specific code into options.c.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 107 +++++++++-------------------------------------------
net/dccp/ackvec.h | 5 +-
net/dccp/options.c | 65 +++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+), 92 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -108,7 +108,7 @@ extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
u64 *ackno, const u8 opt,
const u8 *value, const u8 len);
-extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb);
+extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
{
@@ -151,8 +151,7 @@ static inline int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
return -1;
}
-static inline int dccp_insert_option_ackvec(const struct sock *sk,
- const struct sk_buff *skb)
+static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 nonce)
{
return -1;
}
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -54,106 +54,35 @@ void dccp_ackvec_free(struct dccp_ackvec *av)
}
}
-static void dccp_ackvec_insert_avr(struct dccp_ackvec *av,
- struct dccp_ackvec_record *avr)
-{
- /*
- * AVRs are sorted by seqno. Since we are sending them in order, we
- * just add the AVR at the head of the list.
- * -sorbo.
- */
- if (!list_empty(&av->av_records)) {
- const struct dccp_ackvec_record *head =
- list_entry(av->av_records.next,
- struct dccp_ackvec_record,
- avr_node);
- BUG_ON(before48(avr->avr_ack_seqno, head->avr_ack_seqno));
- }
-
- list_add(&avr->avr_node, &av->av_records);
-}
-
-int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
+/**
+ * dccp_ackvec_update_records - Record information about sent Ack Vectors
+ * @av: Ack Vector records to update
+ * @seqno: Sequence number of the packet carrying the Ack Vector just sent
+ * @nonce_sum: The sum of all buffer nonces contained in the Ack Vector
+ */
+int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
{
- struct dccp_sock *dp = dccp_sk(sk);
- struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
- /* Figure out how many options do we need to represent the ackvec */
- const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
- u16 len = av->av_vec_len + 2 * nr_opts;
- u8 i, nonce = 0;
- const unsigned char *tail, *from;
- unsigned char *to;
struct dccp_ackvec_record *avr;
- if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
- /*
- * FIXME: when running out of option space while piggybacking on
- * DataAck, return 0 here and schedule a separate Ack instead.
- */
- DCCP_WARN("Lacking space for %u bytes on %s packet\n", len,
- dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
- return -1;
- }
-
avr = kmem_cache_alloc(dccp_ackvec_record_slab, GFP_ATOMIC);
if (avr == NULL)
- return -1;
-
- DCCP_SKB_CB(skb)->dccpd_opt_len += len;
-
- to = skb_push(skb, len);
- len = av->av_vec_len;
- from = av->av_buf + av->av_buf_head;
- tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
-
- for (i = 0; i < nr_opts; ++i) {
- int copylen = len;
-
- if (len > DCCP_SINGLE_OPT_MAXLEN)
- copylen = DCCP_SINGLE_OPT_MAXLEN;
-
- /*
- * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via
- * its type; ack_nonce is the sum of all individual buf_nonce's.
- */
- nonce ^= av->av_buf_nonce[i];
-
- *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i];
- *to++ = copylen + 2;
-
- /* Check if buf_head wraps */
- if (from + copylen > tail) {
- const u16 tailsize = tail - from;
-
- memcpy(to, from, tailsize);
- to += tailsize;
- len -= tailsize;
- copylen -= tailsize;
- from = av->av_buf;
- }
-
- memcpy(to, from, copylen);
- from += copylen;
- to += copylen;
- len -= copylen;
- }
+ return -ENOBUFS;
- /*
- * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340.
- */
- avr->avr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+ avr->avr_ack_seqno = seqno;
avr->avr_ack_ptr = av->av_buf_head;
avr->avr_ack_ackno = av->av_buf_ackno;
- avr->avr_ack_nonce = nonce;
+ avr->avr_ack_nonce = nonce_sum;
avr->avr_ack_runlen = dccp_ackvec_runlen(av->av_buf + av->av_buf_head);
+ /*
+ * Since GSS is incremented for each packet, the list is automatically
+ * arranged in descending order of @ack_seqno.
+ */
+ list_add(&avr->avr_node, &av->av_records);
- dccp_ackvec_insert_avr(av, avr);
-
- dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, "
- "ack_ackno=%llu\n",
- dccp_role(sk), avr->avr_ack_runlen,
+ dccp_pr_debug("Added Vector, ack_seqno=%llu, ack_ackno=%llu (rl=%u)\n",
(unsigned long long)avr->avr_ack_seqno,
- (unsigned long long)avr->avr_ack_ackno);
+ (unsigned long long)avr->avr_ack_ackno,
+ avr->avr_ack_runlen);
return 0;
}
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -433,6 +433,71 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp,
return 0;
}
+int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
+{
+ struct dccp_ackvec *av = dccp_sk(sk)->dccps_hc_rx_ackvec;
+ /* Figure out how many options do we need to represent the ackvec */
+ const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
+ u16 len = av->av_vec_len + 2 * nr_opts;
+ u8 i, nonce = 0;
+ const unsigned char *tail, *from;
+ unsigned char *to;
+
+ if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
+ /*
+ * FIXME: when running out of option space while piggybacking on
+ * DataAck, return 0 here and schedule a separate Ack instead.
+ */
+ DCCP_WARN("Lacking space for %u bytes on %s packet\n", len,
+ dccp_packet_name(DCCP_SKB_CB(skb)->dccpd_type));
+ return -1;
+ }
+ DCCP_SKB_CB(skb)->dccpd_opt_len += len;
+
+ to = skb_push(skb, len);
+ len = av->av_vec_len;
+ from = av->av_buf + av->av_buf_head;
+ tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
+
+ for (i = 0; i < nr_opts; ++i) {
+ int copylen = len;
+
+ if (len > DCCP_SINGLE_OPT_MAXLEN)
+ copylen = DCCP_SINGLE_OPT_MAXLEN;
+
+ /*
+ * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via
+ * its type; ack_nonce is the sum of all individual buf_nonce's.
+ */
+ nonce ^= av->av_buf_nonce[i];
+
+ *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i];
+ *to++ = copylen + 2;
+
+ /* Check if buf_head wraps */
+ if (from + copylen > tail) {
+ const u16 tailsize = tail - from;
+
+ memcpy(to, from, tailsize);
+ to += tailsize;
+ len -= tailsize;
+ copylen -= tailsize;
+ from = av->av_buf;
+ }
+
+ memcpy(to, from, copylen);
+ from += copylen;
+ to += copylen;
+ len -= copylen;
+ }
+ /*
+ * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340.
+ */
+ if (dccp_ackvec_update_records(av, DCCP_SKB_CB(skb)->dccpd_seq, nonce))
+ return -ENOBUFS;
+ return 0;
+}
+
/**
* dccp_insert_option_mandatory - Mandatory option (5.8.2)
* Note that since we are using skb_push, this function needs to be called
--
1.5.3.GIT
^ permalink raw reply
* [PATCH 02/14] [ACKVEC]: Update Ack Vector fields
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-2-git-send-email-gerrit@erg.abdn.ac.uk>
This patch updates the fields used by the Ack Vector structures:
* buf_tail was missing and has been added as struct member (support for
updating this field follows in subsequent patches);
* the buf_nonce is now an array, each element covering up to 253 bytes of
buffer state - this simplifies computing the ECN nonce for large Ack Vectors.
In particular, there are the following changes:
* since buf_nonce and buffer size use the same number, introduced a constant to
set the maximum number of Ack Vectors in the buffer (tried Kconfig, but with
low Ack Ratio rates, a size of 1 is fully sufficient, 2 seems to work for a
wide range of cases; Kconfig remains an option for later);
* removed the field dccpav_ack_nonce from struct dccp_ackvec, since this is
already redundantly stored in the `dccpavr_ack_nonce' (Ack Vector record);
* replaced semantics of dccpavr_sent_len with dccpavr_ack_runlen, since the
code needs to be able to remember the old run length;
* also updated the documentation on sending Ack Vectors, it was outdated
(ack_runlen was not considered);
* all sequence numbers now truncated to 48 bits (the assignment of 2^48 to
buf_ackno in dccp_ackvec_alloc() has been removed, since dccp_ackvec_add()
overrides this value each time a new packet is added to the buffer).
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 48 ++++++++++++++++----------------
net/dccp/ackvec.h | 77 +++++++++++++++++++++++++++--------------------------
2 files changed, 63 insertions(+), 62 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -18,8 +18,14 @@
/* maximum size of a single TLV-encoded option (sans type/len bytes) */
#define DCCP_SINGLE_OPT_MAXLEN 253
-/* We can spread an ack vector across multiple options */
-#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
+/*
+ * Ack Vector buffer space is static, in multiples of %DCCP_SINGLE_OPT_MAXLEN,
+ * the maximum size of a single Ack Vector. Setting %DCCPAV_NUM_ACKVECS to 1
+ * will be sufficient for most cases of low Ack Ratios, using a value of 2 gives
+ * more headroom if Ack Ratio is higher or when the sender acknowledges slowly.
+ */
+#define DCCPAV_NUM_ACKVECS 2
+#define DCCPAV_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * DCCPAV_NUM_ACKVECS)
#define DCCP_ACKVEC_STATE_RECEIVED 0
#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6)
@@ -28,58 +34,53 @@
#define DCCP_ACKVEC_STATE_MASK 0xC0 /* 11000000 */
#define DCCP_ACKVEC_LEN_MASK 0x3F /* 00111111 */
-/** struct dccp_ackvec - ack vector
- *
- * This data structure is the one defined in RFC 4340, Appendix A.
- *
- * @av_buf_head - circular buffer head
- * @av_buf_tail - circular buffer tail
- * @av_buf_ackno - ack # of the most recent packet acknowledgeable in the
- * buffer (i.e. %av_buf_head)
- * @av_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked
- * by the buffer with State 0
+/** struct dccp_ackvec - Ack Vector main data structure
*
- * Additionally, the HC-Receiver must keep some information about the
- * Ack Vectors it has recently sent. For each packet sent carrying an
- * Ack Vector, it remembers four variables:
+ * This implements a fixed-size circular buffer within an array and is largely
+ * based on Appendix A of RFC 4340.
*
- * @av_records - list of dccp_ackvec_record
- * @av_ack_nonce - the one-bit sum of the ECN Nonces for all State 0.
- *
- * @av_time - the time in usecs
- * @av_buf - circular buffer of acknowledgeable packets
+ * @av_buf: circular buffer storage area
+ * @av_buf_head: head index; begin of live portion in @av_buf
+ * @av_buf_tail: tail index; first index _after_ the live portion in @av_buf
+ * @av_buf_ackno: highest seqno of acknowledgeable packet recorded in @av_buf
+ * @av_buf_nonce: ECN nonce sums, each covering subsequent segments of up to
+ * %DCCP_SINGLE_OPT_MAXLEN cells in the live portion of @av_buf
+ * @av_records: list of %dccp_ackvec_record (Ack Vectors sent previously)
+ * @av_time: the time in usecs
+ * @av_veclen: length of the live portion of @av_buf
*/
struct dccp_ackvec {
- u64 av_buf_ackno;
+ u8 av_buf[DCCPAV_MAX_ACKVEC_LEN];
+ u16 av_buf_head;
+ u16 av_buf_tail;
+ u64 av_buf_ackno:48;
+ bool av_buf_nonce[DCCPAV_NUM_ACKVECS];
struct list_head av_records;
ktime_t av_time;
- u16 av_buf_head;
u16 av_vec_len;
- u8 av_buf_nonce;
- u8 av_ack_nonce;
- u8 av_buf[DCCP_MAX_ACKVEC_LEN];
};
-/** struct dccp_ackvec_record - ack vector record
+/** struct dccp_ackvec_record - Records information about sent Ack Vectors
*
- * ACK vector record as defined in Appendix A of spec.
+ * These list entries define the additional information which the HC-Receiver
+ * keeps about recently-sent Ack Vectors; again refer to RFC 4340, Appendix A.
*
- * The list is sorted by avr_ack_seqno
+ * @avr_node: the list node in @av_records
+ * @avr_ack_seqno: sequence number of the packet the Ack Vector was sent on
+ * @avr_ack_ackno: the Ack number that this record/Ack Vector refers to
+ * @avr_ack_ptr: pointer into @av_buf where this record starts
+ * @avr_ack_runlen: run length of @avr_ack_ptr at the time of sending
+ * @avr_ack_nonce: the sum of @av_buf_nonce's at the time this record was sent
*
- * @avr_node - node in av_records
- * @avr_ack_seqno - sequence number of the packet this record was sent on
- * @avr_ack_ackno - sequence number being acknowledged
- * @avr_ack_ptr - pointer into av_buf where this record starts
- * @avr_ack_nonce - av_ack_nonce at the time this record was sent
- * @avr_sent_len - lenght of the record in av_buf
+ * The list as a whole is sorted in descending order by @avr_ack_seqno.
*/
struct dccp_ackvec_record {
struct list_head avr_node;
- u64 avr_ack_seqno;
- u64 avr_ack_ackno;
+ u64 avr_ack_seqno:48;
+ u64 avr_ack_ackno:48;
u16 avr_ack_ptr;
- u16 avr_sent_len;
- u8 avr_ack_nonce;
+ u8 avr_ack_runlen;
+ u8 avr_ack_nonce:1;
};
struct sock;
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -69,7 +69,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec;
/* Figure out how many options do we need to represent the ackvec */
const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN);
- u16 len = av->av_vec_len + 2 * nr_opts, i;
+ u16 len = av->av_vec_len + 2 * nr_opts;
+ u8 i, nonce = 0;
u32 elapsed_time;
const unsigned char *tail, *from;
unsigned char *to;
@@ -102,7 +103,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
to = skb_push(skb, len);
len = av->av_vec_len;
from = av->av_buf + av->av_buf_head;
- tail = av->av_buf + DCCP_MAX_ACKVEC_LEN;
+ tail = av->av_buf + DCCPAV_MAX_ACKVEC_LEN;
for (i = 0; i < nr_opts; ++i) {
int copylen = len;
@@ -110,7 +111,13 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
if (len > DCCP_SINGLE_OPT_MAXLEN)
copylen = DCCP_SINGLE_OPT_MAXLEN;
- *to++ = DCCPO_ACK_VECTOR_0;
+ /*
+ * RFC 4340, 12.2: Encode the Nonce Echo for this Ack Vector via
+ * its type; ack_nonce is the sum of all individual buf_nonce's.
+ */
+ nonce ^= av->av_buf_nonce[i];
+
+ *to++ = DCCPO_ACK_VECTOR_0 + av->av_buf_nonce[i];
*to++ = copylen + 2;
/* Check if buf_head wraps */
@@ -131,25 +138,19 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
}
/*
- * From RFC 4340, A.2:
- *
- * For each acknowledgement it sends, the HC-Receiver will add an
- * acknowledgement record. ack_seqno will equal the HC-Receiver
- * sequence number it used for the ack packet; ack_ptr will equal
- * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will
- * equal buf_nonce.
+ * Each sent Ack Vector is recorded in the list, as per A.2 of RFC 4340.
*/
- avr->avr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
- avr->avr_ack_ptr = av->av_buf_head;
- avr->avr_ack_ackno = av->av_buf_ackno;
- avr->avr_ack_nonce = av->av_buf_nonce;
- avr->avr_sent_len = av->av_vec_len;
+ avr->avr_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq;
+ avr->avr_ack_ptr = av->av_buf_head;
+ avr->avr_ack_ackno = av->av_buf_ackno;
+ avr->avr_ack_nonce = nonce;
+ avr->avr_ack_runlen = av->av_buf[av->av_buf_head] & DCCP_ACKVEC_LEN_MASK;
dccp_ackvec_insert_avr(av, avr);
dccp_pr_debug("%s ACK Vector 0, len=%d, ack_seqno=%llu, "
"ack_ackno=%llu\n",
- dccp_role(sk), avr->avr_sent_len,
+ dccp_role(sk), avr->avr_ack_runlen,
(unsigned long long)avr->avr_ack_seqno,
(unsigned long long)avr->avr_ack_ackno);
return 0;
@@ -160,11 +161,10 @@ struct dccp_ackvec *dccp_ackvec_alloc(const gfp_t priority)
struct dccp_ackvec *av = kmem_cache_alloc(dccp_ackvec_slab, priority);
if (av != NULL) {
- av->av_buf_head = DCCP_MAX_ACKVEC_LEN - 1;
- av->av_buf_ackno = UINT48_MAX + 1;
- av->av_buf_nonce = 0;
+ av->av_buf_head = DCCPAV_MAX_ACKVEC_LEN - 1;
av->av_time = ktime_set(0, 0);
av->av_vec_len = 0;
+ memset(av->av_buf_nonce, 0, sizeof(av->av_buf_nonce));
INIT_LIST_HEAD(&av->av_records);
}
@@ -212,7 +212,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
unsigned int gap;
long new_head;
- if (av->av_vec_len + packets > DCCP_MAX_ACKVEC_LEN)
+ if (av->av_vec_len + packets > DCCPAV_MAX_ACKVEC_LEN)
return -ENOBUFS;
gap = packets - 1;
@@ -224,7 +224,7 @@ static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av,
gap + new_head + 1);
gap = -new_head;
}
- new_head += DCCP_MAX_ACKVEC_LEN;
+ new_head += DCCPAV_MAX_ACKVEC_LEN;
}
av->av_buf_head = new_head;
@@ -315,7 +315,7 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
goto out_duplicate;
delta -= len + 1;
- if (++index == DCCP_MAX_ACKVEC_LEN)
+ if (++index == DCCPAV_MAX_ACKVEC_LEN)
index = 0;
}
}
@@ -366,7 +366,7 @@ static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
if (av->av_buf_head <= avr->avr_ack_ptr)
av->av_vec_len = avr->avr_ack_ptr - av->av_buf_head;
else
- av->av_vec_len = DCCP_MAX_ACKVEC_LEN - 1 -
+ av->av_vec_len = DCCPAV_MAX_ACKVEC_LEN - 1 -
av->av_buf_head + avr->avr_ack_ptr;
/* free records */
@@ -390,7 +390,7 @@ void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk,
if (ackno == avr->avr_ack_seqno) {
dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, "
"ack_ackno=%llu, ACKED!\n",
- dccp_role(sk), 1,
+ dccp_role(sk), avr->avr_ack_runlen,
(unsigned long long)avr->avr_ack_seqno,
(unsigned long long)avr->avr_ack_ackno);
dccp_ackvec_throw_record(av, avr);
^ permalink raw reply
* [PATCH 07/14] [ACKVEC]: Unnecessary to parse Ack Vectors when clearing HC-receiver state
From: Gerrit Renker @ 2007-12-19 14:25 UTC (permalink / raw)
To: acme; +Cc: dccp, netdev, Gerrit Renker
In-Reply-To: <1198074355-18842-7-git-send-email-gerrit@erg.abdn.ac.uk>
This removes code clearing Ack Vector state when it is acknowledged via an
Ack Vector by the peer. That code is redundant, since
* the receiver always puts the full acknowledgment window (groups 2,3 in 11.4.2)
into the Ack Vectors it sends; hence the HC-receiver is only interested in the
highest state that the HC-sender received;
* this means that the acknowledgment number on the (Data)Ack from the HC-sender
is sufficient; and work done in parsing earlier state is not necessary, since
the later state subsumes the earlier one (see also RFC 4340, A.4).
Other (minor) changes:
* uses the suggestion made in the code comment, to traverse from oldest record
to youngest - allowing faster hits when the list is large;
* removed the unused argument variable `sk' from check_rcv_ackno;
* renamed check_rcv_ackno => clear_state, since then it is clearer
what is done by the function (also same name as in A.3 of RFC 4340);
* the variable `ackno' now becomes unused in options.c, and therefore
is now used for other (space-saving) purposes.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
---
net/dccp/ackvec.c | 114 ++++++++++------------------------------------------
net/dccp/ackvec.h | 17 +-------
net/dccp/input.c | 4 +-
net/dccp/options.c | 12 ++----
4 files changed, 30 insertions(+), 117 deletions(-)
--- a/net/dccp/ackvec.h
+++ b/net/dccp/ackvec.h
@@ -102,13 +102,8 @@ extern void dccp_ackvec_free(struct dccp_ackvec *av);
extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
const u64 ackno, const u8 state);
-extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av,
- struct sock *sk, const u64 ackno);
-extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
- u64 *ackno, const u8 opt,
- const u8 *value, const u8 len);
-
extern int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 sum);
+extern void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno);
static inline int dccp_ackvec_pending(const struct dccp_ackvec *av)
{
@@ -139,18 +134,10 @@ static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
return -1;
}
-static inline void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av,
- struct sock *sk, const u64 ackno)
+static inline void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
{
}
-static inline int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
- const u64 *ackno, const u8 opt,
- const u8 *value, const u8 len)
-{
- return -1;
-}
-
static inline int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seq, u8 nonce)
{
return -1;
--- a/net/dccp/ackvec.c
+++ b/net/dccp/ackvec.c
@@ -86,6 +86,24 @@ int dccp_ackvec_update_records(struct dccp_ackvec *av, u64 seqno, u8 nonce_sum)
return 0;
}
+static struct dccp_ackvec_record *dccp_ackvec_lookup(struct list_head *av_list,
+ const u64 ackno)
+{
+ struct dccp_ackvec_record *avr;
+ /*
+ * Exploit that records are inserted in descending order of sequence
+ * number, start with the oldest record first. If @ackno is `before'
+ * the earliest ack_ackno, the packet is too old (or is a duplicate).
+ */
+ list_for_each_entry_reverse(avr, av_list, avr_node) {
+ if (avr->avr_ack_seqno == ackno)
+ return avr;
+ if (before48(ackno, avr->avr_ack_seqno))
+ break;
+ }
+ return NULL;
+}
+
/*
* If several packets are missing, the HC-Receiver may prefer to enter multiple
* bytes with run length 0, rather than a single byte with a larger run length;
@@ -234,101 +252,13 @@ static void dccp_ackvec_throw_record(struct dccp_ackvec *av,
}
}
-void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk,
- const u64 ackno)
-{
- struct dccp_ackvec_record *avr;
-
- /*
- * If we traverse backwards, it should be faster when we have large
- * windows. We will be receiving ACKs for stuff we sent a while back
- * -sorbo.
- */
- list_for_each_entry_reverse(avr, &av->av_records, avr_node) {
- if (ackno == avr->avr_ack_seqno) {
- dccp_pr_debug("%s ACK packet 0, len=%d, ack_seqno=%llu, "
- "ack_ackno=%llu, ACKED!\n",
- dccp_role(sk), avr->avr_ack_runlen,
- (unsigned long long)avr->avr_ack_seqno,
- (unsigned long long)avr->avr_ack_ackno);
- dccp_ackvec_throw_record(av, avr);
- break;
- } else if (avr->avr_ack_seqno > ackno)
- break; /* old news */
- }
-}
-
-static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av,
- struct sock *sk, u64 *ackno,
- const unsigned char len,
- const unsigned char *vector)
+void dccp_ackvec_clear_state(struct dccp_ackvec *av, const u64 ackno)
{
- unsigned char i;
struct dccp_ackvec_record *avr;
- /* Check if we actually sent an ACK vector */
- if (list_empty(&av->av_records))
- return;
-
- i = len;
- /*
- * XXX
- * I think it might be more efficient to work backwards. See comment on
- * rcv_ackno. -sorbo.
- */
- avr = list_entry(av->av_records.next, struct dccp_ackvec_record, avr_node);
- while (i--) {
- const u8 rl = dccp_ackvec_runlen(vector);
- u64 ackno_end_rl;
-
- dccp_set_seqno(&ackno_end_rl, *ackno - rl);
-
- /*
- * If our AVR sequence number is greater than the ack, go
- * forward in the AVR list until it is not so.
- */
- list_for_each_entry_from(avr, &av->av_records, avr_node) {
- if (!after48(avr->avr_ack_seqno, *ackno))
- goto found;
- }
- /* End of the av_records list, not found, exit */
- break;
-found:
- if (between48(avr->avr_ack_seqno, ackno_end_rl, *ackno)) {
- if (dccp_ackvec_state(vector) !=
- DCCP_ACKVEC_STATE_NOT_RECEIVED) {
- dccp_pr_debug("%s ACK vector 0, len=%d, "
- "ack_seqno=%llu, ack_ackno=%llu, "
- "ACKED!\n",
- dccp_role(sk), len,
- (unsigned long long)
- avr->avr_ack_seqno,
- (unsigned long long)
- avr->avr_ack_ackno);
- dccp_ackvec_throw_record(av, avr);
- break;
- }
- /*
- * If it wasn't received, continue scanning... we might
- * find another one.
- */
- }
-
- dccp_set_seqno(ackno, ackno_end_rl - 1);
- ++vector;
- }
-}
-
-int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb,
- u64 *ackno, const u8 opt, const u8 *value, const u8 len)
-{
- if (len > DCCP_SINGLE_OPT_MAXLEN)
- return -1;
-
- /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */
- dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec, sk,
- ackno, len, value);
- return 0;
+ avr = dccp_ackvec_lookup(&av->av_records, ackno);
+ if (avr != NULL)
+ dccp_ackvec_throw_record(av, avr);
}
int __init dccp_ackvec_init(void)
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -164,8 +164,8 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
struct dccp_sock *dp = dccp_sk(sk);
if (dp->dccps_hc_rx_ackvec != NULL)
- dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk,
- DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ dccp_ackvec_clear_state(dp->dccps_hc_rx_ackvec,
+ DCCP_SKB_CB(skb)->dccpd_ack_seq);
}
static void dccp_deliver_input_to_ccids(struct sock *sk, struct sk_buff *skb)
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -138,9 +138,8 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
case DCCPO_ACK_VECTOR_1:
if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */
break;
- if (dp->dccps_hc_rx_ackvec != NULL &&
- dccp_ackvec_parse(sk, skb, &ackno, opt, value, len))
- goto out_invalid_option;
+ dccp_pr_debug("%s Ack Vector (len=%u)\n", dccp_role(sk),
+ len);
break;
case DCCPO_TIMESTAMP:
if (len != 4)
@@ -166,8 +165,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
}
dccp_pr_debug("%s rx opt: TIMESTAMP=%u, ackno=%llu\n",
dccp_role(sk), ntohl(opt_val),
- (unsigned long long)
- DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ (unsigned long long)ackno);
/* schedule an Ack in case this sender is quiescent */
dccp_schedule_ack(sk);
break;
@@ -181,9 +179,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
dccp_pr_debug("%s rx opt: TIMESTAMP_ECHO=%u, len=%d, "
"ackno=%llu", dccp_role(sk),
opt_recv->dccpor_timestamp_echo,
- len + 2,
- (unsigned long long)
- DCCP_SKB_CB(skb)->dccpd_ack_seq);
+ len + 2, (unsigned long long)ackno);
value += 4;
--
1.5.3.GIT
^ permalink raw reply
* Re: [Bugme-new] [Bug 9543] New: RTNL: assertion failed at net/ipv6/addrconf.c (2164)/RTNL: assertion failed at net/ipv4/devinet.c (1055)
From: Andy Gospodarek @ 2007-12-19 14:42 UTC (permalink / raw)
To: Krzysztof Oledzki
Cc: Andy Gospodarek, Jay Vosburgh, Herbert Xu, Andrew Morton,
bugme-daemon, shemminger, davem, netdev
In-Reply-To: <Pine.LNX.4.64.0712182052490.24949@bizon.gios.gov.pl>
On Tue, Dec 18, 2007 at 08:53:39PM +0100, Krzysztof Oledzki wrote:
>
>
> On Fri, 14 Dec 2007, Andy Gospodarek wrote:
>
> >On Fri, Dec 14, 2007 at 07:57:42PM +0100, Krzysztof Oledzki wrote:
> >>
> >>
> >>On Fri, 14 Dec 2007, Andy Gospodarek wrote:
> >>
> >>>On Fri, Dec 14, 2007 at 05:14:57PM +0100, Krzysztof Oledzki wrote:
> >>>>
> >>>>
> >>>>On Wed, 12 Dec 2007, Jay Vosburgh wrote:
> >>>>
> >>>>>Herbert Xu <herbert@gondor.apana.org.au> wrote:
> >>>>>
> >>>>>>>diff -puN drivers/net/bonding/bond_sysfs.c~bonding-locking-fix
> >>>>>>>drivers/net/bonding/bond_sysfs.c
> >>>>>>>--- a/drivers/net/bonding/bond_sysfs.c~bonding-locking-fix
> >>>>>>>+++ a/drivers/net/bonding/bond_sysfs.c
> >>>>>>>@@ -1111,8 +1111,6 @@ static ssize_t bonding_store_primary(str
> >>>>>>>out:
> >>>>>>> write_unlock_bh(&bond->lock);
> >>>>>>>
> >>>>>>>- rtnl_unlock();
> >>>>>>>-
> >>>>>>
> >>>>>>Looking at the changeset that added this perhaps the intention
> >>>>>>is to hold the lock? If so we should add an rtnl_lock to the start
> >>>>>>of the function.
> >>>>>
> >>>>> Yes, this function needs to hold locks, and more than just
> >>>>>what's there now. I believe the following should be correct; I haven't
> >>>>>tested it, though (I'm supposedly on vacation right now).
> >>>>>
> >>>>> The following change should be correct for the
> >>>>>bonding_store_primary case discussed in this thread, and also corrects
> >>>>>the bonding_store_active case which performs similar functions.
> >>>>>
> >>>>> The bond_change_active_slave and bond_select_active_slave
> >>>>>functions both require rtnl, bond->lock for read and curr_slave_lock
> >>>>>for
> >>>>>write_bh, and no other locks. This is so that the lower level
> >>>>>mode-specific functions can release locks down to just rtnl in order to
> >>>>>call, e.g., dev_set_mac_address with the locks it expects (rtnl only).
> >>>>>
> >>>>>Signed-off-by: Jay Vosburgh <fubar@us.ibm.com>
> >>>>>
> >>>>>diff --git a/drivers/net/bonding/bond_sysfs.c
> >>>>>b/drivers/net/bonding/bond_sysfs.c
> >>>>>index 11b76b3..28a2d80 100644
> >>>>>--- a/drivers/net/bonding/bond_sysfs.c
> >>>>>+++ b/drivers/net/bonding/bond_sysfs.c
> >>>>>@@ -1075,7 +1075,10 @@ static ssize_t bonding_store_primary(struct
> >>>>>device
> >>>>>*d,
> >>>>> struct slave *slave;
> >>>>> struct bonding *bond = to_bond(d);
> >>>>>
> >>>>>- write_lock_bh(&bond->lock);
> >>>>>+ rtnl_lock();
> >>>>>+ read_lock(&bond->lock);
> >>>>>+ write_lock_bh(&bond->curr_slave_lock);
> >>>>>+
> >>>>> if (!USES_PRIMARY(bond->params.mode)) {
> >>>>> printk(KERN_INFO DRV_NAME
> >>>>> ": %s: Unable to set primary slave; %s is in mode
> >>>>> %d\n",
> >>>>>@@ -1109,8 +1112,8 @@ static ssize_t bonding_store_primary(struct
> >>>>>device
> >>>>>*d,
> >>>>> }
> >>>>> }
> >>>>>out:
> >>>>>- write_unlock_bh(&bond->lock);
> >>>>>-
> >>>>>+ write_unlock_bh(&bond->curr_slave_lock);
> >>>>>+ read_unlock(&bond->lock);
> >>>>> rtnl_unlock();
> >>>>>
> >>>>> return count;
> >>>>>@@ -1190,7 +1193,8 @@ static ssize_t bonding_store_active_slave(struct
> >>>>>device *d,
> >>>>> struct bonding *bond = to_bond(d);
> >>>>>
> >>>>> rtnl_lock();
> >>>>>- write_lock_bh(&bond->lock);
> >>>>>+ read_lock(&bond->lock);
> >>>>>+ write_lock_bh(&bond->curr_slave_lock);
> >>>>>
> >>>>> if (!USES_PRIMARY(bond->params.mode)) {
> >>>>> printk(KERN_INFO DRV_NAME
> >>>>>@@ -1247,7 +1251,8 @@ static ssize_t bonding_store_active_slave(struct
> >>>>>device *d,
> >>>>> }
> >>>>> }
> >>>>>out:
> >>>>>- write_unlock_bh(&bond->lock);
> >>>>>+ write_unlock_bh(&bond->curr_slave_lock);
> >>>>>+ read_unlock(&bond->lock);
> >>>>> rtnl_unlock();
> >>>>>
> >>>>> return count;
> >>>>
> >>>>Vanilla 2.6.24-rc5 plus this patch:
> >>>>
> >>>>=========================================================
> >>>>[ INFO: possible irq lock inversion dependency detected ]
> >>>>2.6.24-rc5 #1
> >>>>---------------------------------------------------------
> >>>>events/0/9 just changed the state of lock:
> >>>>(&mc->mca_lock){-+..}, at: [<c0411c7a>] mld_ifc_timer_expire+0x130/0x1fb
> >>>>but this lock took another, soft-read-irq-unsafe lock in the past:
> >>>>(&bond->lock){-.--}
> >>>>
> >>>>and interrupts could create inverse lock ordering between them.
> >>>>
> >>>>
> >>>
> >>>Grrr, I should have seen that -- sorry. Try your luck with this instead:
> >><CUT>
> >>
> >>No luck.
> >>
> >
> >
> >I'm guessing if we go back to using a write-lock for bond->lock this
> >will go back to working again, but I'm not totally convinced since there
> >are plenty of places where we used a read-lock with it.
>
> Should I check this patch or rather, based on a future discussion, wait
> for another version?
>
> >
> >diff --git a/drivers/net/bonding/bond_sysfs.c
> >b/drivers/net/bonding/bond_sysfs.c
> >index 11b76b3..635b857 100644
> >--- a/drivers/net/bonding/bond_sysfs.c
> >+++ b/drivers/net/bonding/bond_sysfs.c
> >@@ -1075,7 +1075,10 @@ static ssize_t bonding_store_primary(struct device
> >*d,
> > struct slave *slave;
> > struct bonding *bond = to_bond(d);
> >
> >+ rtnl_lock();
> > write_lock_bh(&bond->lock);
> >+ write_lock_bh(&bond->curr_slave_lock);
> >+
> > if (!USES_PRIMARY(bond->params.mode)) {
> > printk(KERN_INFO DRV_NAME
> > ": %s: Unable to set primary slave; %s is in mode
> > %d\n",
> >@@ -1109,8 +1112,8 @@ static ssize_t bonding_store_primary(struct device
> >*d,
> > }
> > }
> >out:
> >+ write_unlock_bh(&bond->curr_slave_lock);
> > write_unlock_bh(&bond->lock);
> >-
> > rtnl_unlock();
> >
> > return count;
> >@@ -1191,6 +1194,7 @@ static ssize_t bonding_store_active_slave(struct
> >device *d,
> >
> > rtnl_lock();
> > write_lock_bh(&bond->lock);
> >+ write_lock_bh(&bond->curr_slave_lock);
> >
> > if (!USES_PRIMARY(bond->params.mode)) {
> > printk(KERN_INFO DRV_NAME
> >@@ -1247,6 +1251,7 @@ static ssize_t bonding_store_active_slave(struct
> >device *d,
> > }
> > }
> >out:
> >+ write_unlock_bh(&bond->curr_slave_lock);
> > write_unlock_bh(&bond->lock);
> > rtnl_unlock();
> >
>
>
> Best regards,
>
> Krzysztof Olędzki
For now, I prefer Jay's original patch -- with the read_locks (rather
than read/write_lock_bh) and the added rtnl_lock. There is still a
lockdep issue that we need to sort-out, but this patch is needed first.
^ permalink raw reply
* [patch 0/2][NETNS] prepare the neigh subsys to handle network namespaces
From: Daniel Lezcano @ 2007-12-19 14:55 UTC (permalink / raw)
To: davem; +Cc: netdev, den, benjamin.thery
These two patches are coming from Eric Biederman patchset
to make the neighbouring to be aware of the namespaces.
The description in the patch headers is big enough to add
more comments here :)
--
^ permalink raw reply
* [patch 1/2][NETNS] net: Modify the neighbour table code so it handles multiple network namespaces
From: Daniel Lezcano @ 2007-12-19 14:55 UTC (permalink / raw)
To: davem; +Cc: netdev, den, benjamin.thery, Eric W. Biederman
In-Reply-To: <20071219145544.184198087@ICON-9-164-138-215.megacenter.de.ibm.com>
[-- Attachment #1: 0001-net-Modify-the-neighbour-table-code-so-it-handles-m.patch --]
[-- Type: text/plain, Size: 21219 bytes --]
I'm actually surprised at how much was involved. At first glance it appears
that the neighbour table data structures are already split by network device
so all that should be needed is to modify the user interface commands
to filter the set of neighbours by the network namespace of their devices.
However a couple things turned up while I was reading through the code.
The proxy neighbour table allows entries with no network device, and
the neighbour parms are per network device (except for the defaults)
so they now need a per network namespace default.
So I updated the two structures (which surprised me) with their very
own network namespace parameter. Updated the relevant lookup and
destroy routines with a network namespace parameter and modified
the code that interacts with users to filter out neighbour
table entries for devices of other namespaces.
I'm a little concerned that we can modify and display the global
table configuration and from all network namespaces. But
this appears good enough for now.
I keep thinking modifying the neighbour table to have per network
namespace instances of each table type would should be cleaner. The
hash table is already dynamically sized so there are it is not a limiter.
The default parameter would be straight forward to take care of. However
when I look at the how the network table is built and used I still find
some assumptions that there is only a single neighbour table for each
type of table in the kernel. The netlink operations, neigh_seq_start,
the non-core network users that call neigh_lookup. So while it might
be doable it would require more refactoring than my current approach
of just doing a little extra filtering in the code.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
include/net/neighbour.h | 13 +++--
net/atm/clip.c | 15 +++++-
net/core/neighbour.c | 115 +++++++++++++++++++++++++++++-------------------
net/decnet/dn_neigh.c | 35 +++++++++++++-
net/decnet/dn_route.c | 2
net/ipv4/arp.c | 12 ++---
net/ipv6/ip6_output.c | 2
net/ipv6/ndisc.c | 4 -
8 files changed, 136 insertions(+), 62 deletions(-)
Index: net-2.6.25/include/net/neighbour.h
===================================================================
--- net-2.6.25.orig/include/net/neighbour.h
+++ net-2.6.25/include/net/neighbour.h
@@ -34,6 +34,7 @@ struct neighbour;
struct neigh_parms
{
+ struct net *net;
struct net_device *dev;
struct neigh_parms *next;
int (*neigh_setup)(struct neighbour *);
@@ -126,7 +127,8 @@ struct neigh_ops
struct pneigh_entry
{
struct pneigh_entry *next;
- struct net_device *dev;
+ struct net *net;
+ struct net_device *dev;
u8 flags;
u8 key[0];
};
@@ -187,6 +189,7 @@ extern struct neighbour * neigh_lookup(s
const void *pkey,
struct net_device *dev);
extern struct neighbour * neigh_lookup_nodev(struct neigh_table *tbl,
+ struct net *net,
const void *pkey);
extern struct neighbour * neigh_create(struct neigh_table *tbl,
const void *pkey,
@@ -211,15 +214,17 @@ extern unsigned long neigh_rand_reach_t
extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p,
struct sk_buff *skb);
-extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, const void *key, struct net_device *dev, int creat);
-extern int pneigh_delete(struct neigh_table *tbl, const void *key, struct net_device *dev);
+extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev, int creat);
+extern int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev);
extern void neigh_app_ns(struct neighbour *n);
extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie);
extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *));
extern void pneigh_for_each(struct neigh_table *tbl, void (*cb)(struct pneigh_entry *));
-struct neigh_seq_state {
+struct neigh_seq_state
+{
+ struct net *net;
struct neigh_table *tbl;
void *(*neigh_sub_iter)(struct neigh_seq_state *state,
struct neighbour *n, loff_t *pos);
Index: net-2.6.25/net/atm/clip.c
===================================================================
--- net-2.6.25.orig/net/atm/clip.c
+++ net-2.6.25/net/atm/clip.c
@@ -949,6 +949,11 @@ static int arp_seq_open(struct inode *in
seq = file->private_data;
seq->private = state;
+ state->ns.net = get_proc_net(inode);
+ if (!state->ns.net) {
+ seq_release_private(inode, file);
+ rc = -ENXIO;
+ }
out:
return rc;
@@ -957,11 +962,19 @@ out_kfree:
goto out;
}
+static int arp_seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct clip_seq_state *state = seq->private;
+ put_net(state->ns.net);
+ return seq_release_private(inode, file);
+}
+
static const struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = arp_seq_release,
.owner = THIS_MODULE
};
#endif
Index: net-2.6.25/net/core/neighbour.c
===================================================================
--- net-2.6.25.orig/net/core/neighbour.c
+++ net-2.6.25/net/core/neighbour.c
@@ -365,7 +365,7 @@ struct neighbour *neigh_lookup(struct ne
return n;
}
-struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey)
+struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net * net, const void *pkey)
{
struct neighbour *n;
int key_len = tbl->key_len;
@@ -375,7 +375,8 @@ struct neighbour *neigh_lookup_nodev(str
read_lock_bh(&tbl->lock);
for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
- if (!memcmp(n->primary_key, pkey, key_len)) {
+ if (!memcmp(n->primary_key, pkey, key_len) &&
+ (net == n->dev->nd_net)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
break;
@@ -453,7 +454,8 @@ out_neigh_release:
goto out;
}
-struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, const void *pkey,
+struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl,
+ struct net * net, const void *pkey,
struct net_device *dev, int creat)
{
struct pneigh_entry *n;
@@ -469,6 +471,7 @@ struct pneigh_entry * pneigh_lookup(stru
for (n = tbl->phash_buckets[hash_val]; n; n = n->next) {
if (!memcmp(n->key, pkey, key_len) &&
+ (n->net == net) &&
(n->dev == dev || !n->dev)) {
read_unlock_bh(&tbl->lock);
goto out;
@@ -485,6 +488,7 @@ struct pneigh_entry * pneigh_lookup(stru
if (!n)
goto out;
+ n->net = hold_net(net);
memcpy(n->key, pkey, key_len);
n->dev = dev;
if (dev)
@@ -507,7 +511,7 @@ out:
}
-int pneigh_delete(struct neigh_table *tbl, const void *pkey,
+int pneigh_delete(struct neigh_table *tbl, struct net * net, const void *pkey,
struct net_device *dev)
{
struct pneigh_entry *n, **np;
@@ -522,13 +526,15 @@ int pneigh_delete(struct neigh_table *tb
write_lock_bh(&tbl->lock);
for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL;
np = &n->next) {
- if (!memcmp(n->key, pkey, key_len) && n->dev == dev) {
+ if (!memcmp(n->key, pkey, key_len) && n->dev == dev &&
+ (n->net == net)) {
*np = n->next;
write_unlock_bh(&tbl->lock);
if (tbl->pdestructor)
tbl->pdestructor(n);
if (n->dev)
dev_put(n->dev);
+ release_net(n->net);
kfree(n);
return 0;
}
@@ -551,6 +557,7 @@ static int pneigh_ifdown(struct neigh_ta
tbl->pdestructor(n);
if (n->dev)
dev_put(n->dev);
+ release_net(n->net);
kfree(n);
continue;
}
@@ -1264,12 +1271,37 @@ void pneigh_enqueue(struct neigh_table *
spin_unlock(&tbl->proxy_queue.lock);
}
+static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
+ struct net * net, int ifindex)
+{
+ struct neigh_parms *p;
+
+ for (p = &tbl->parms; p; p = p->next) {
+ if (p->net != net)
+ continue;
+ if ((p->dev && p->dev->ifindex == ifindex) ||
+ (!p->dev && !ifindex))
+ return p;
+ }
+
+ return NULL;
+}
struct neigh_parms *neigh_parms_alloc(struct net_device *dev,
struct neigh_table *tbl)
{
- struct neigh_parms *p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL);
+ struct neigh_parms *p, *ref;
+ struct net * net;
+
+ net = &init_net;
+ if (dev)
+ net = dev->nd_net;
+
+ ref = lookup_neigh_params(tbl, net, 0);
+ if (!ref)
+ return NULL;
+ p = kmemdup(ref, sizeof(*p), GFP_KERNEL);
if (p) {
p->tbl = tbl;
atomic_set(&p->refcnt, 1);
@@ -1285,6 +1317,7 @@ struct neigh_parms *neigh_parms_alloc(st
dev_hold(dev);
p->dev = dev;
}
+ p->net = hold_net(net);
p->sysctl_table = NULL;
write_lock_bh(&tbl->lock);
p->next = tbl->parms.next;
@@ -1326,6 +1359,7 @@ void neigh_parms_release(struct neigh_ta
void neigh_parms_destroy(struct neigh_parms *parms)
{
+ release_net(parms->net);
kfree(parms);
}
@@ -1336,6 +1370,7 @@ void neigh_table_init_no_netlink(struct
unsigned long now = jiffies;
unsigned long phsize;
+ tbl->parms.net = &init_net;
atomic_set(&tbl->parms.refcnt, 1);
INIT_RCU_HEAD(&tbl->parms.rcu_head);
tbl->parms.reachable_time =
@@ -1449,9 +1484,6 @@ static int neigh_delete(struct sk_buff *
struct net_device *dev = NULL;
int err = -EINVAL;
- if (net != &init_net)
- return -EINVAL;
-
if (nlmsg_len(nlh) < sizeof(*ndm))
goto out;
@@ -1480,7 +1512,7 @@ static int neigh_delete(struct sk_buff *
goto out_dev_put;
if (ndm->ndm_flags & NTF_PROXY) {
- err = pneigh_delete(tbl, nla_data(dst_attr), dev);
+ err = pneigh_delete(tbl, net, nla_data(dst_attr), dev);
goto out_dev_put;
}
@@ -1518,9 +1550,6 @@ static int neigh_add(struct sk_buff *skb
struct net_device *dev = NULL;
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL);
if (err < 0)
goto out;
@@ -1560,7 +1589,7 @@ static int neigh_add(struct sk_buff *skb
struct pneigh_entry *pn;
err = -ENOBUFS;
- pn = pneigh_lookup(tbl, dst, dev, 1);
+ pn = pneigh_lookup(tbl, net, dst, dev, 1);
if (pn) {
pn->flags = ndm->ndm_flags;
err = 0;
@@ -1755,19 +1784,6 @@ errout:
return -EMSGSIZE;
}
-static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl,
- int ifindex)
-{
- struct neigh_parms *p;
-
- for (p = &tbl->parms; p; p = p->next)
- if ((p->dev && p->dev->ifindex == ifindex) ||
- (!p->dev && !ifindex))
- return p;
-
- return NULL;
-}
-
static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = {
[NDTA_NAME] = { .type = NLA_STRING },
[NDTA_THRESH1] = { .type = NLA_U32 },
@@ -1801,9 +1817,6 @@ static int neightbl_set(struct sk_buff *
struct nlattr *tb[NDTA_MAX+1];
int err;
- if (net != &init_net)
- return -EINVAL;
-
err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX,
nl_neightbl_policy);
if (err < 0)
@@ -1848,7 +1861,7 @@ static int neightbl_set(struct sk_buff *
if (tbp[NDTPA_IFINDEX])
ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]);
- p = lookup_neigh_params(tbl, ifindex);
+ p = lookup_neigh_params(tbl, net, ifindex);
if (p == NULL) {
err = -ENOENT;
goto errout_tbl_lock;
@@ -1929,9 +1942,6 @@ static int neightbl_dump_info(struct sk_
int neigh_skip = cb->args[1];
struct neigh_table *tbl;
- if (net != &init_net)
- return 0;
-
family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
read_lock(&neigh_tbl_lock);
@@ -1946,8 +1956,11 @@ static int neightbl_dump_info(struct sk_
NLM_F_MULTI) <= 0)
break;
- for (nidx = 0, p = tbl->parms.next; p; p = p->next, nidx++) {
- if (nidx < neigh_skip)
+ for (nidx = 0, p = tbl->parms.next; p; p = p->next) {
+ if (net != p->net)
+ continue;
+
+ if (nidx++ < neigh_skip)
continue;
if (neightbl_fill_param_info(skb, tbl, p,
@@ -2023,6 +2036,7 @@ static void neigh_update_notify(struct n
static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
struct netlink_callback *cb)
{
+ struct net * net = skb->sk->sk_net;
struct neighbour *n;
int rc, h, s_h = cb->args[1];
int idx, s_idx = idx = cb->args[2];
@@ -2033,8 +2047,12 @@ static int neigh_dump_table(struct neigh
continue;
if (h > s_h)
s_idx = 0;
- for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {
- if (idx < s_idx)
+ for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) {
+ int lidx;
+ if (n->dev->nd_net != net)
+ continue;
+ lidx = idx++;
+ if (lidx < s_idx)
continue;
if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
@@ -2056,13 +2074,9 @@ out:
static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb)
{
- struct net *net = skb->sk->sk_net;
struct neigh_table *tbl;
int t, family, s_t;
- if (net != &init_net)
- return 0;
-
read_lock(&neigh_tbl_lock);
family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family;
s_t = cb->args[0];
@@ -2130,6 +2144,7 @@ EXPORT_SYMBOL(__neigh_for_each_release);
static struct neighbour *neigh_get_first(struct seq_file *seq)
{
struct neigh_seq_state *state = seq->private;
+ struct net * net = state->net;
struct neigh_table *tbl = state->tbl;
struct neighbour *n = NULL;
int bucket = state->bucket;
@@ -2139,6 +2154,8 @@ static struct neighbour *neigh_get_first
n = tbl->hash_buckets[bucket];
while (n) {
+ if (n->dev->nd_net != net)
+ goto next;
if (state->neigh_sub_iter) {
loff_t fakep = 0;
void *v;
@@ -2168,6 +2185,7 @@ static struct neighbour *neigh_get_next(
loff_t *pos)
{
struct neigh_seq_state *state = seq->private;
+ struct net * net = state->net;
struct neigh_table *tbl = state->tbl;
if (state->neigh_sub_iter) {
@@ -2179,6 +2197,8 @@ static struct neighbour *neigh_get_next(
while (1) {
while (n) {
+ if (n->dev->nd_net != net)
+ goto next;
if (state->neigh_sub_iter) {
void *v = state->neigh_sub_iter(state, n, pos);
if (v)
@@ -2225,6 +2245,7 @@ static struct neighbour *neigh_get_idx(s
static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
{
struct neigh_seq_state *state = seq->private;
+ struct net * net = state->net;
struct neigh_table *tbl = state->tbl;
struct pneigh_entry *pn = NULL;
int bucket = state->bucket;
@@ -2232,6 +2253,8 @@ static struct pneigh_entry *pneigh_get_f
state->flags |= NEIGH_SEQ_IS_PNEIGH;
for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) {
pn = tbl->phash_buckets[bucket];
+ while (pn && (pn->net != net))
+ pn = pn->next;
if (pn)
break;
}
@@ -2245,6 +2268,7 @@ static struct pneigh_entry *pneigh_get_n
loff_t *pos)
{
struct neigh_seq_state *state = seq->private;
+ struct net * net = state->net;
struct neigh_table *tbl = state->tbl;
pn = pn->next;
@@ -2252,6 +2276,8 @@ static struct pneigh_entry *pneigh_get_n
if (++state->bucket > PNEIGH_HASHMASK)
break;
pn = tbl->phash_buckets[state->bucket];
+ while (pn && (pn->net != net))
+ pn = pn->next;
if (pn)
break;
}
@@ -2453,6 +2479,7 @@ static inline size_t neigh_nlmsg_size(vo
static void __neigh_notify(struct neighbour *n, int type, int flags)
{
+ struct net * net = n->dev->nd_net;
struct sk_buff *skb;
int err = -ENOBUFS;
@@ -2467,10 +2494,10 @@ static void __neigh_notify(struct neighb
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, &init_net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+ err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
errout:
if (err < 0)
- rtnl_set_sk_err(&init_net, RTNLGRP_NEIGH, err);
+ rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
}
#ifdef CONFIG_ARPD
Index: net-2.6.25/net/decnet/dn_neigh.c
===================================================================
--- net-2.6.25.orig/net/decnet/dn_neigh.c
+++ net-2.6.25/net/decnet/dn_neigh.c
@@ -580,8 +580,37 @@ static const struct seq_operations dn_ne
static int dn_neigh_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &dn_neigh_seq_ops,
- sizeof(struct neigh_seq_state));
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+ struct neigh_seq_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
+
+ if (!s)
+ goto out;
+
+ rc = seq_open(file, &dn_neigh_seq_ops);
+ if (rc)
+ goto out_kfree;
+
+ seq = file->private_data;
+ seq->private = s;
+ s->net = get_proc_net(inode);
+ if (!s->net) {
+ seq_release_private(inode, file);
+ rc = -ENXIO;
+ }
+out:
+ return rc;
+out_kfree:
+ kfree(s);
+ goto out;
+}
+
+static int dn_neigh_seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ struct neigh_seq_state *state = seq->private;
+ put_net(state->net);
+ return seq_release_private(inode, file);
}
static const struct file_operations dn_neigh_seq_fops = {
@@ -589,7 +618,7 @@ static const struct file_operations dn_n
.open = dn_neigh_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = dn_neigh_seq_release,
};
#endif
Index: net-2.6.25/net/decnet/dn_route.c
===================================================================
--- net-2.6.25.orig/net/decnet/dn_route.c
+++ net-2.6.25/net/decnet/dn_route.c
@@ -984,7 +984,7 @@ source_ok:
* here
*/
if (!try_hard) {
- neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst);
+ neigh = neigh_lookup_nodev(&dn_neigh_table, &init_net, &fl.fld_dst);
if (neigh) {
if ((oldflp->oif &&
(neigh->dev->ifindex != oldflp->oif)) ||
Index: net-2.6.25/net/ipv4/arp.c
===================================================================
--- net-2.6.25.orig/net/ipv4/arp.c
+++ net-2.6.25/net/ipv4/arp.c
@@ -838,7 +838,7 @@ static int arp_process(struct sk_buff *s
} else if (IN_DEV_FORWARD(in_dev)) {
if ((rt->rt_flags&RTCF_DNAT) ||
(addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
- (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &tip, dev, 0)))) {
+ (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &init_net, &tip, dev, 0)))) {
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
if (n)
neigh_release(n);
@@ -981,7 +981,7 @@ static int arp_req_set_public(struct net
return -ENODEV;
}
if (mask) {
- if (pneigh_lookup(&arp_tbl, &ip, dev, 1) == NULL)
+ if (pneigh_lookup(&arp_tbl, &init_net, &ip, dev, 1) == NULL)
return -ENOBUFS;
return 0;
}
@@ -1090,7 +1090,7 @@ static int arp_req_delete_public(struct
__be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
if (mask == htonl(0xFFFFFFFF))
- return pneigh_delete(&arp_tbl, &ip, dev);
+ return pneigh_delete(&arp_tbl, &init_net, &ip, dev);
if (mask)
return -EINVAL;
@@ -1376,8 +1376,8 @@ static const struct seq_operations arp_s
static int arp_seq_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &arp_seq_ops,
- sizeof(struct neigh_seq_state));
+ return seq_open_net(inode, file, &arp_seq_ops,
+ sizeof(struct neigh_seq_state));
}
static const struct file_operations arp_seq_fops = {
@@ -1385,7 +1385,7 @@ static const struct file_operations arp_
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
static int __init arp_proc_init(void)
Index: net-2.6.25/net/ipv6/ip6_output.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ip6_output.c
+++ net-2.6.25/net/ipv6/ip6_output.c
@@ -449,7 +449,7 @@ int ip6_forward(struct sk_buff *skb)
/* XXX: idev->cnf.proxy_ndp? */
if (ipv6_devconf.proxy_ndp &&
- pneigh_lookup(&nd_tbl, &hdr->daddr, skb->dev, 0)) {
+ pneigh_lookup(&nd_tbl, &init_net, &hdr->daddr, skb->dev, 0)) {
int proxied = ip6_forward_proxy_check(skb);
if (proxied > 0)
return ip6_input(skb);
Index: net-2.6.25/net/ipv6/ndisc.c
===================================================================
--- net-2.6.25.orig/net/ipv6/ndisc.c
+++ net-2.6.25/net/ipv6/ndisc.c
@@ -789,7 +789,7 @@ static void ndisc_recv_ns(struct sk_buff
if (ipv6_chk_acast_addr(dev, &msg->target) ||
(idev->cnf.forwarding &&
(ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) &&
- (pneigh = pneigh_lookup(&nd_tbl,
+ (pneigh = pneigh_lookup(&nd_tbl, &init_net,
&msg->target, dev, 0)) != NULL)) {
if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) &&
skb->pkt_type != PACKET_HOST &&
@@ -930,7 +930,7 @@ static void ndisc_recv_na(struct sk_buff
*/
if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) &&
ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
- pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
+ pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) {
/* XXX: idev->cnf.prixy_ndp */
goto out;
}
--
^ permalink raw reply
* [patch 2/2][NETNS] net: Add a helper function neigh_param_default_alloc
From: Daniel Lezcano @ 2007-12-19 14:55 UTC (permalink / raw)
To: davem; +Cc: netdev, den, benjamin.thery, Eric W. Biederman
In-Reply-To: <20071219145544.184198087@ICON-9-164-138-215.megacenter.de.ibm.com>
[-- Attachment #1: 0002-net-Add-a-helper-function-neigh_param_default_alloc.patch --]
[-- Type: text/plain, Size: 2127 bytes --]
In the presence of multiple network namespaces the logic needed
to allocate the a default parameter table is just barely non-trivial.
So add a function to automate it to make everyone's life easier.
Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
---
include/net/neighbour.h | 1 +
net/core/neighbour.c | 15 +++++++++++++++
2 files changed, 16 insertions(+)
Index: net-2.6.25/include/net/neighbour.h
===================================================================
--- net-2.6.25.orig/include/net/neighbour.h
+++ net-2.6.25/include/net/neighbour.h
@@ -208,6 +208,7 @@ extern struct neighbour *neigh_event_ns
struct net_device *dev);
extern struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl);
+extern struct neigh_parms *neigh_parms_alloc_default(struct neigh_table *tbl, struct net *net);
extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms);
extern void neigh_parms_destroy(struct neigh_parms *parms);
extern unsigned long neigh_rand_reach_time(unsigned long base);
Index: net-2.6.25/net/core/neighbour.c
===================================================================
--- net-2.6.25.orig/net/core/neighbour.c
+++ net-2.6.25/net/core/neighbour.c
@@ -1327,6 +1327,20 @@ struct neigh_parms *neigh_parms_alloc(st
return p;
}
+struct neigh_parms *neigh_parms_alloc_default(struct neigh_table *tbl,
+ struct net *net)
+{
+ struct neigh_parms *parms;
+ if (net != &init_net) {
+ parms = neigh_parms_alloc(NULL, tbl);
+ release_net(parms->net);
+ parms->net = hold_net(net);
+ }
+ else
+ parms = neigh_parms_clone(&tbl->parms);
+ return parms;
+}
+
static void neigh_rcu_free_parms(struct rcu_head *head)
{
struct neigh_parms *parms =
@@ -2789,6 +2803,7 @@ EXPORT_SYMBOL(neigh_ifdown);
EXPORT_SYMBOL(neigh_lookup);
EXPORT_SYMBOL(neigh_lookup_nodev);
EXPORT_SYMBOL(neigh_parms_alloc);
+EXPORT_SYMBOL(neigh_parms_alloc_default);
EXPORT_SYMBOL(neigh_parms_release);
EXPORT_SYMBOL(neigh_rand_reach_time);
EXPORT_SYMBOL(neigh_resolve_output);
--
^ permalink raw reply
* Re: [PATCH] [IPv6]: IPV6_MULTICAST_IF setting is ignored on link-local connect()
From: Vlad Yasevich @ 2007-12-19 15:20 UTC (permalink / raw)
To: David Stevens
Cc: Brian Haley, David Miller, netdev@vger.kernel.org, netdev-owner,
YOSHIFUJI Hideaki
In-Reply-To: <OF7B1ADDCA.711DCE7B-ON882573B5.00820D67-882573B5.0083AEF8@us.ibm.com>
Daven
David Stevens wrote:
> Brian,
>
> OK, I see what you're trying to fix now.
>
> I think the scope_id checks are not quite right-- they
> should be something like this:
>
> if (addr_type&IPV6_ADDR_LINKLOCAL) {
> if (addr_len >= sizeof(struct sockaddr_in6)) {
> if (sk->sk_bound_dev_if && usin->sin6_scope_id &&
> sk->sk_bound_dev_if != usin->sin6_scope_id) {
> err = -EINVAL;
> goto out;
> }
> if (usin->sin6_scope_id)
> sk->sk_bound_dev_if = usin->sin6_scope_id;
> if (!sk->sk_bound_dev_if &&
> (addr_type & IPV6_ADDR_MULTICAST))
> fl.oif = np->mcast_oif;
> }
>
> /* connect to the link-local addres requires an interface */
> if (!sk->sk_bound_dev_if) {
> err = -EINVAL;
> goto out;
> }
> }
But this still requires either a SO_BINDTODEVICE or sin6_scope_id. This
means the an application can call BINDTODEVICE(eth0), MULTICAST_IF(eth1)
issue a connect on a UDP socket an succeed? Seems wrong to me.
Can you check section 6.7 of RFC 3542.
Thanks
-vlad
>
> That is (in English):
>
> If I did an SO_BINDTODEVICE and specified sin6_scope_id,
> then they better agree.
> If I specified sin6_scope_id without SO_BINDTODEVICE, set
> the device to that.
> If I get this far without a device and it's multicast, use
> mcast_oif
> If I get all through that and don't have a device, EINVAL.
>
> Does that work for you?
>
> +-DLS
>
> --
> 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
>
^ permalink raw reply
* [PATCH netns-2.6.25 0/19] routing virtualization
From: Denis V. Lunev @ 2007-12-19 15:21 UTC (permalink / raw)
To: David Miller
Cc: netdev, Linux Containers, Benjamin Thery,
xemul-GEFAQzZX7r8dnm+yROfE0A
Hi, David!
This set adds namespace support for routing tables & rules manipulation
in the different namespaces. So, one could create a namespace and
setup IPv4 routing there how he wants.
After this patch user will have the ability to configure and
observe its own isolated set of routing rules/tables, but they
all will be unused. I.e. routing decisions inside the network
stack are still made based on the init_net's rules. The reason for doing
so is to have something self-consistent and not too huge :)
The sequence is the following:
- viritualize generic FIB rules operations
- change IPv4 FIB initialization sequence
- virtualize FIB tables access
After this, the 'ip' utility and the /proc interface will start
working correctly inside a namespace, while the 'route' utility
will not, because IP sockets currently cannot be created in non-init
namespace.
Regards,
Den
^ permalink raw reply
* [PATCH net-2.6.25 15/19] [NETNS] Provide correct namespace for fibnl netlink socket.
From: Denis V. Lunev @ 2007-12-19 15:24 UTC (permalink / raw)
To: davem; +Cc: benjamin.thery, dlezcano, devel, containers, netdev, xemul
In-Reply-To: <4769370F.5020303@openvz.org>
Acked-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
include/net/netns/ipv4.h | 2 ++
net/ipv4/fib_frontend.c | 26 ++++++++++++++++++--------
2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 629ec6c..031d761 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -9,6 +9,7 @@ struct ctl_table_header;
struct ipv4_devconf;
struct fib_rules_ops;
struct hlist_head;
+struct sock;
struct netns_ipv4 {
struct ctl_table_header *forw_hdr;
@@ -18,5 +19,6 @@ struct netns_ipv4 {
struct fib_rules_ops *rules_ops;
#endif
struct hlist_head *fib_table_hash;
+ struct sock *fibnl;
};
#endif
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 2e150ae..abe9f43 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -49,8 +49,6 @@
#define FFprint(a...) printk(KERN_DEBUG a)
-static struct sock *fibnl;
-
#ifndef CONFIG_IP_MULTIPLE_TABLES
static int __net_init fib4_rules_init(struct net *net)
@@ -845,11 +843,13 @@ static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
static void nl_fib_input(struct sk_buff *skb)
{
+ struct net *net;
struct fib_result_nl *frn;
struct nlmsghdr *nlh;
struct fib_table *tb;
u32 pid;
+ net = skb->sk->sk_net;
nlh = nlmsg_hdr(skb);
if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
@@ -858,26 +858,36 @@ static void nl_fib_input(struct sk_buff *skb)
}
frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
- tb = fib_get_table(&init_net, frn->tb_id_in);
+ tb = fib_get_table(net, frn->tb_id_in);
nl_fib_lookup(frn, tb);
pid = NETLINK_CB(skb).pid; /* pid of sending process */
NETLINK_CB(skb).pid = 0; /* from kernel */
NETLINK_CB(skb).dst_group = 0; /* unicast */
- netlink_unicast(fibnl, skb, pid, MSG_DONTWAIT);
+ netlink_unicast(net->ipv4.fibnl, skb, pid, MSG_DONTWAIT);
}
static int nl_fib_lookup_init(struct net *net)
{
- fibnl = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
- nl_fib_input, NULL, THIS_MODULE);
- return fibnl != NULL ? 0 : -EAFNOSUPPORT;
+ struct sock *sk;
+ sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, 0,
+ nl_fib_input, NULL, THIS_MODULE);
+ if (sk == NULL)
+ return -EAFNOSUPPORT;
+ /* Don't hold an extra reference on the namespace */
+ put_net(sk->sk_net);
+ net->ipv4.fibnl = sk;
+ return 0;
}
static void nl_fib_lookup_exit(struct net *net)
{
- sock_put(fibnl);
+ /* At the last minute lie and say this is a socket for the
+ * initial network namespace. So the socket will be safe to free.
+ */
+ net->ipv4.fibnl->sk_net = get_net(&init_net);
+ sock_put(net->ipv4.fibnl);
}
static void fib_disable_ip(struct net_device *dev, int force)
--
1.5.3.rc5
^ permalink raw reply related
* [PATCH net-2.6.25 17/19] [NETNS] Pass namespace through ip_rt_ioctl.
From: Denis V. Lunev @ 2007-12-19 15:24 UTC (permalink / raw)
To: davem; +Cc: benjamin.thery, dlezcano, devel, containers, netdev, xemul
In-Reply-To: <4769370F.5020303@openvz.org>
... up to rtentry_to_fib_config
Acked-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
include/net/route.h | 2 +-
net/ipv4/af_inet.c | 2 +-
net/ipv4/fib_frontend.c | 8 ++++----
net/ipv4/ipconfig.c | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/include/net/route.h b/include/net/route.h
index b777000..5847e6f 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -120,7 +120,7 @@ extern void ip_rt_send_redirect(struct sk_buff *skb);
extern unsigned inet_addr_type(struct net *net, __be32 addr);
extern unsigned inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr);
extern void ip_rt_multicast_event(struct in_device *);
-extern int ip_rt_ioctl(unsigned int cmd, void __user *arg);
+extern int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg);
extern void ip_rt_get_source(u8 *src, struct rtable *rt);
extern int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 6fac905..f0968a1 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -793,7 +793,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCADDRT:
case SIOCDELRT:
case SIOCRTMSG:
- err = ip_rt_ioctl(cmd, (void __user *)arg);
+ err = ip_rt_ioctl(sk->sk_net, cmd, (void __user *)arg);
break;
case SIOCDARP:
case SIOCGARP:
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index cecb660..a5c47fc 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -437,7 +437,7 @@ static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt,
* Handle IP routing ioctl calls. These are used to manipulate the routing tables
*/
-int ip_rt_ioctl(unsigned int cmd, void __user *arg)
+int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg)
{
struct fib_config cfg;
struct rtentry rt;
@@ -453,18 +453,18 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
return -EFAULT;
rtnl_lock();
- err = rtentry_to_fib_config(&init_net, cmd, &rt, &cfg);
+ err = rtentry_to_fib_config(net, cmd, &rt, &cfg);
if (err == 0) {
struct fib_table *tb;
if (cmd == SIOCDELRT) {
- tb = fib_get_table(&init_net, cfg.fc_table);
+ tb = fib_get_table(net, cfg.fc_table);
if (tb)
err = tb->tb_delete(tb, &cfg);
else
err = -ESRCH;
} else {
- tb = fib_new_table(&init_net, cfg.fc_table);
+ tb = fib_new_table(net, cfg.fc_table);
if (tb)
err = tb->tb_insert(tb, &cfg);
else
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 7288adb..7a89247 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -302,7 +302,7 @@ static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg)
mm_segment_t oldfs = get_fs();
set_fs(get_ds());
- res = ip_rt_ioctl(cmd, (void __user *) arg);
+ res = ip_rt_ioctl(&init_net, cmd, (void __user *) arg);
set_fs(oldfs);
return res;
}
--
1.5.3.rc5
^ permalink raw reply related
* [PATCH net-2.6.25 7/19] [IPV4] Unify access to the routing tables.
From: Denis V. Lunev @ 2007-12-19 15:24 UTC (permalink / raw)
To: davem; +Cc: benjamin.thery, dlezcano, devel, containers, netdev, xemul
In-Reply-To: <4769370F.5020303@openvz.org>
Replace the direct pointers to local and main tables with
calls to fib_get_table() with appropriate argument.
This doesn't introduce additional dereferences, but makes the access to fib
tables uniform in any (CONFIG_IP_MULTIPLE_TABLES) case.
Acked-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
include/net/ip_fib.h | 39 ++++++++++++++++++++++++++++-----------
net/ipv4/fib_frontend.c | 29 ++++++++++++-----------------
2 files changed, 40 insertions(+), 28 deletions(-)
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 338d3ed..06e6a33 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -120,16 +120,22 @@ struct fib_result_nl {
int err;
};
+extern struct hlist_head fib_table_hash[];
+
#ifdef CONFIG_IP_ROUTE_MULTIPATH
#define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel])
#define FIB_RES_RESET(res) ((res).nh_sel = 0)
+#define FIB_TABLE_HASHSZ 2
+
#else /* CONFIG_IP_ROUTE_MULTIPATH */
#define FIB_RES_NH(res) ((res).fi->fib_nh[0])
#define FIB_RES_RESET(res)
+#define FIB_TABLE_HASHSZ 256
+
#endif /* CONFIG_IP_ROUTE_MULTIPATH */
#define FIB_RES_PREFSRC(res) ((res).fi->fib_prefsrc ? : __fib_res_prefsrc(&res))
@@ -156,14 +162,17 @@ struct fib_table {
#ifndef CONFIG_IP_MULTIPLE_TABLES
-extern struct fib_table *ip_fib_local_table;
-extern struct fib_table *ip_fib_main_table;
+#define TABLE_LOCAL_INDEX 0
+#define TABLE_MAIN_INDEX 1
static inline struct fib_table *fib_get_table(u32 id)
{
- if (id != RT_TABLE_LOCAL)
- return ip_fib_main_table;
- return ip_fib_local_table;
+ struct hlist_head *ptr;
+
+ ptr = id == RT_TABLE_LOCAL ?
+ &fib_table_hash[TABLE_LOCAL_INDEX] :
+ &fib_table_hash[TABLE_MAIN_INDEX];
+ return hlist_entry(ptr->first, struct fib_table, tb_hlist);
}
static inline struct fib_table *fib_new_table(u32 id)
@@ -173,16 +182,24 @@ static inline struct fib_table *fib_new_table(u32 id)
static inline int fib_lookup(const struct flowi *flp, struct fib_result *res)
{
- if (ip_fib_local_table->tb_lookup(ip_fib_local_table, flp, res) &&
- ip_fib_main_table->tb_lookup(ip_fib_main_table, flp, res))
- return -ENETUNREACH;
- return 0;
+ struct fib_table *table;
+
+ table = fib_get_table(RT_TABLE_LOCAL);
+ if (!table->tb_lookup(table, flp, res))
+ return 0;
+
+ table = fib_get_table(RT_TABLE_MAIN);
+ if (!table->tb_lookup(table, flp, res))
+ return 0;
+ return -ENETUNREACH;
}
-static inline void fib_select_default(const struct flowi *flp, struct fib_result *res)
+static inline void fib_select_default(const struct flowi *flp,
+ struct fib_result *res)
{
+ struct fib_table *table = fib_get_table(RT_TABLE_MAIN);
if (FIB_RES_GW(*res) && FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
- ip_fib_main_table->tb_select_default(ip_fib_main_table, flp, res);
+ table->tb_select_default(table, flp, res);
}
#else /* CONFIG_IP_MULTIPLE_TABLES */
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 714fff9..df9716f 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -50,39 +50,34 @@
#define FFprint(a...) printk(KERN_DEBUG a)
static struct sock *fibnl;
+struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
#ifndef CONFIG_IP_MULTIPLE_TABLES
-struct fib_table *ip_fib_local_table;
-struct fib_table *ip_fib_main_table;
-
-#define FIB_TABLE_HASHSZ 1
-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
-
static int __net_init fib4_rules_init(struct net *net)
{
- ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);
- if (ip_fib_local_table == NULL)
+ struct fib_table *local_table, *main_table;
+
+ local_table = fib_hash_init(RT_TABLE_LOCAL);
+ if (local_table == NULL)
return -ENOMEM;
- ip_fib_main_table = fib_hash_init(RT_TABLE_MAIN);
- if (ip_fib_main_table == NULL)
+ main_table = fib_hash_init(RT_TABLE_MAIN);
+ if (main_table == NULL)
goto fail;
- hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]);
- hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]);
+ hlist_add_head_rcu(&local_table->tb_hlist,
+ &fib_table_hash[TABLE_LOCAL_INDEX]);
+ hlist_add_head_rcu(&main_table->tb_hlist,
+ &fib_table_hash[TABLE_MAIN_INDEX]);
return 0;
fail:
- kfree(ip_fib_local_table);
- ip_fib_local_table = NULL;
+ kfree(local_table);
return -ENOMEM;
}
#else
-#define FIB_TABLE_HASHSZ 256
-static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];
-
struct fib_table *fib_new_table(u32 id)
{
struct fib_table *tb;
--
1.5.3.rc5
^ permalink raw reply related
* [PATCH net-2.6.25 2/19] [NETNS] Pass fib_rules_ops into default_pref method.
From: Denis V. Lunev @ 2007-12-19 15:24 UTC (permalink / raw)
To: davem; +Cc: benjamin.thery, dlezcano, devel, containers, netdev, xemul
In-Reply-To: <4769370F.5020303@openvz.org>
fib_rules_ops contains operations and the list of configured rules. ops will
become per/namespace soon, so we need them to be known in the default_pref
callback.
Acked-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Denis V. Lunev <den@openvz.org>
---
include/net/fib_rules.h | 2 +-
net/core/fib_rules.c | 2 +-
net/decnet/dn_rules.c | 2 +-
net/ipv4/fib_rules.c | 2 +-
net/ipv6/fib6_rules.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index af62345..14b8a71 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -56,7 +56,7 @@ struct fib_rules_ops
int (*fill)(struct fib_rule *, struct sk_buff *,
struct nlmsghdr *,
struct fib_rule_hdr *);
- u32 (*default_pref)(void);
+ u32 (*default_pref)(struct fib_rules_ops *ops);
size_t (*nlmsg_payload)(struct fib_rule *);
/* Called after modifications to the rules set, must flush
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index ada9c81..e12e9f5 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -285,7 +285,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
rule->table = frh_get_table(frh, tb);
if (!rule->pref && ops->default_pref)
- rule->pref = ops->default_pref();
+ rule->pref = ops->default_pref(ops);
err = -EINVAL;
if (tb[FRA_GOTO]) {
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index 0b5e2b9..c1fae23 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -212,7 +212,7 @@ nla_put_failure:
return -ENOBUFS;
}
-static u32 dn_fib_rule_default_pref(void)
+static u32 dn_fib_rule_default_pref(struct fib_rules_ops *ops)
{
struct list_head *pos;
struct fib_rule *rule;
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index eac3f71..afe669d 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -245,7 +245,7 @@ nla_put_failure:
return -ENOBUFS;
}
-static u32 fib4_rule_default_pref(void)
+static u32 fib4_rule_default_pref(struct fib_rules_ops *ops)
{
struct list_head *pos;
struct fib_rule *rule;
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index e4d7e5a..76437a1 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -223,7 +223,7 @@ nla_put_failure:
return -ENOBUFS;
}
-static u32 fib6_rule_default_pref(void)
+static u32 fib6_rule_default_pref(struct fib_rules_ops *ops)
{
return 0x3FFF;
}
--
1.5.3.rc5
^ permalink raw reply related
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