]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge branch 'dccp' of git://eden-feed.erg.abdn.ac.uk/net-next-2.6
authorDavid S. Miller <davem@davemloft.net>
Tue, 21 Sep 2010 23:00:40 +0000 (16:00 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 21 Sep 2010 23:00:40 +0000 (16:00 -0700)
include/linux/dccp.h
net/dccp/ccid.h
net/dccp/ccids/ccid3.c
net/dccp/ccids/ccid3.h
net/dccp/ccids/lib/tfrc.h
net/dccp/ccids/lib/tfrc_equation.c
net/dccp/options.c

index 7434a8353e2301dcb548ad94965ef0e73390335f..7187bd8a75f62c23b13ac73f4416488a0e42a0c7 100644 (file)
@@ -165,8 +165,10 @@ enum {
        DCCPO_TIMESTAMP_ECHO = 42,
        DCCPO_ELAPSED_TIME = 43,
        DCCPO_MAX = 45,
-       DCCPO_MIN_CCID_SPECIFIC = 128,
-       DCCPO_MAX_CCID_SPECIFIC = 255,
+       DCCPO_MIN_RX_CCID_SPECIFIC = 128,       /* from sender to receiver */
+       DCCPO_MAX_RX_CCID_SPECIFIC = 191,
+       DCCPO_MIN_TX_CCID_SPECIFIC = 192,       /* from receiver to sender */
+       DCCPO_MAX_TX_CCID_SPECIFIC = 255,
 };
 /* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */
 #define DCCP_SINGLE_OPT_MAXLEN 253
index 6df6f8ac963664e2174b55c890ce7f45cbe05128..6d16a9070ff0efdad03c61b4237f7c64601ee2e1 100644 (file)
@@ -62,18 +62,14 @@ struct ccid_operations {
        void            (*ccid_hc_tx_exit)(struct sock *sk);
        void            (*ccid_hc_rx_packet_recv)(struct sock *sk,
                                                  struct sk_buff *skb);
-       int             (*ccid_hc_rx_parse_options)(struct sock *sk,
-                                                   unsigned char option,
-                                                   unsigned char len, u16 idx,
-                                                   unsigned char* value);
+       int             (*ccid_hc_rx_parse_options)(struct sock *sk, u8 pkt,
+                                                   u8 opt, u8 *val, u8 len);
        int             (*ccid_hc_rx_insert_options)(struct sock *sk,
                                                     struct sk_buff *skb);
        void            (*ccid_hc_tx_packet_recv)(struct sock *sk,
                                                  struct sk_buff *skb);
-       int             (*ccid_hc_tx_parse_options)(struct sock *sk,
-                                                   unsigned char option,
-                                                   unsigned char len, u16 idx,
-                                                   unsigned char* value);
+       int             (*ccid_hc_tx_parse_options)(struct sock *sk, u8 pkt,
+                                                   u8 opt, u8 *val, u8 len);
        int             (*ccid_hc_tx_send_packet)(struct sock *sk,
                                                  struct sk_buff *skb);
        void            (*ccid_hc_tx_packet_sent)(struct sock *sk,
@@ -168,27 +164,31 @@ static inline void ccid_hc_tx_packet_recv(struct ccid *ccid, struct sock *sk,
                ccid->ccid_ops->ccid_hc_tx_packet_recv(sk, skb);
 }
 
+/**
+ * ccid_hc_tx_parse_options  -  Parse CCID-specific options sent by the receiver
+ * @pkt: type of packet that @opt appears on (RFC 4340, 5.1)
+ * @opt: the CCID-specific option type (RFC 4340, 5.8 and 10.3)
+ * @val: value of @opt
+ * @len: length of @val in bytes
+ */
 static inline int ccid_hc_tx_parse_options(struct ccid *ccid, struct sock *sk,
-                                          unsigned char option,
-                                          unsigned char len, u16 idx,
-                                          unsigned char* value)
+                                          u8 pkt, u8 opt, u8 *val, u8 len)
 {
-       int rc = 0;
-       if (ccid->ccid_ops->ccid_hc_tx_parse_options != NULL)
-               rc = ccid->ccid_ops->ccid_hc_tx_parse_options(sk, option, len, idx,
-                                                   value);
-       return rc;
+       if (ccid->ccid_ops->ccid_hc_tx_parse_options == NULL)
+               return 0;
+       return ccid->ccid_ops->ccid_hc_tx_parse_options(sk, pkt, opt, val, len);
 }
 
+/**
+ * ccid_hc_rx_parse_options  -  Parse CCID-specific options sent by the sender
+ * Arguments are analogous to ccid_hc_tx_parse_options()
+ */
 static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
-                                          unsigned char option,
-                                          unsigned char len, u16 idx,
-                                          unsigned char* value)
+                                          u8 pkt, u8 opt, u8 *val, u8 len)
 {
-       int rc = 0;
-       if (ccid->ccid_ops->ccid_hc_rx_parse_options != NULL)
-               rc = ccid->ccid_ops->ccid_hc_rx_parse_options(sk, option, len, idx, value);
-       return rc;
+       if (ccid->ccid_ops->ccid_hc_rx_parse_options == NULL)
+               return 0;
+       return ccid->ccid_ops->ccid_hc_rx_parse_options(sk, pkt, opt, val, len);
 }
 
 static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
index ce80591300707c86b91a213922b6b392973b3c40..c3f3a25bbd7aa4f111bda3f56f196e9e5a621f4e 100644 (file)
@@ -54,7 +54,6 @@ static const char *ccid3_tx_state_name(enum ccid3_hc_tx_states state)
        [TFRC_SSTATE_NO_SENT]  = "NO_SENT",
        [TFRC_SSTATE_NO_FBACK] = "NO_FBACK",
        [TFRC_SSTATE_FBACK]    = "FBACK",
-       [TFRC_SSTATE_TERM]     = "TERM",
        };
 
        return ccid3_state_names[state];
@@ -208,10 +207,13 @@ static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
        ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
                       ccid3_tx_state_name(hc->tx_state));
 
+       /* Ignore and do not restart after leaving the established state */
+       if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
+               goto out;
+
+       /* Reset feedback state to "no feedback received" */
        if (hc->tx_state == TFRC_SSTATE_FBACK)
                ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
-       else if (hc->tx_state != TFRC_SSTATE_NO_FBACK)
-               goto out;
 
        /*
         * Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
@@ -287,8 +289,7 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
        if (unlikely(skb->len == 0))
                return -EBADMSG;
 
-       switch (hc->tx_state) {
-       case TFRC_SSTATE_NO_SENT:
+       if (hc->tx_state == TFRC_SSTATE_NO_SENT) {
                sk_reset_timer(sk, &hc->tx_no_feedback_timer, (jiffies +
                               usecs_to_jiffies(TFRC_INITIAL_TIMEOUT)));
                hc->tx_last_win_count   = 0;
@@ -323,9 +324,8 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
                ccid3_update_send_interval(hc);
 
                ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);
-               break;
-       case TFRC_SSTATE_NO_FBACK:
-       case TFRC_SSTATE_FBACK:
+
+       } else {
                delay = ktime_us_delta(hc->tx_t_nom, now);
                ccid3_pr_debug("delay=%ld\n", (long)delay);
                /*
@@ -340,10 +340,6 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb)
                        return (u32)delay / USEC_PER_MSEC;
 
                ccid3_hc_tx_update_win_count(hc, now);
-               break;
-       case TFRC_SSTATE_TERM:
-               DCCP_BUG("%s(%p) - Illegal state TERM", dccp_role(sk), sk);
-               return -EINVAL;
        }
 
        /* prepare to send now (add options etc.) */
@@ -369,21 +365,15 @@ static void ccid3_hc_tx_packet_sent(struct sock *sk, int more,
 static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
-       struct ccid3_options_received *opt_recv = &hc->tx_options_received;
        struct tfrc_tx_hist_entry *acked;
        ktime_t now;
        unsigned long t_nfb;
-       u32 pinv, r_sample;
+       u32 r_sample;
 
        /* we are only interested in ACKs */
        if (!(DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_ACK ||
              DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_DATAACK))
                return;
-       /* ... and only in the established state */
-       if (hc->tx_state != TFRC_SSTATE_FBACK &&
-           hc->tx_state != TFRC_SSTATE_NO_FBACK)
-               return;
-
        /*
         * Locate the acknowledged packet in the TX history.
         *
@@ -403,17 +393,6 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
        r_sample  = dccp_sample_rtt(sk, ktime_us_delta(now, acked->stamp));
        hc->tx_rtt = tfrc_ewma(hc->tx_rtt, r_sample, 9);
 
-       /* Update receive rate in units of 64 * bytes/second */
-       hc->tx_x_recv = opt_recv->ccid3or_receive_rate;
-       hc->tx_x_recv <<= 6;
-
-       /* Update loss event rate (which is scaled by 1e6) */
-       pinv = opt_recv->ccid3or_loss_event_rate;
-       if (pinv == ~0U || pinv == 0)          /* see RFC 4342, 8.5   */
-               hc->tx_p = 0;
-       else                                   /* can not exceed 100% */
-               hc->tx_p = scaled_div(1, pinv);
-
        /*
         * Update allowed sending rate X as per draft rfc3448bis-00, 4.2/3
         */
@@ -481,30 +460,36 @@ done_computing_x:
                           jiffies + usecs_to_jiffies(t_nfb));
 }
 
-static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
-                                    unsigned char len, u16 idx,
-                                    unsigned char *value)
+static int ccid3_hc_tx_parse_options(struct sock *sk, u8 packet_type,
+                                    u8 option, u8 *optval, u8 optlen)
 {
        struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
-       struct ccid3_options_received *opt_recv = &hc->tx_options_received;
        __be32 opt_val;
 
        switch (option) {
        case TFRC_OPT_RECEIVE_RATE:
        case TFRC_OPT_LOSS_EVENT_RATE:
-               if (unlikely(len != 4)) {
+               /* Must be ignored on Data packets, cf. RFC 4342 8.3 and 8.5 */
+               if (packet_type == DCCP_PKT_DATA)
+                       break;
+               if (unlikely(optlen != 4)) {
                        DCCP_WARN("%s(%p), invalid len %d for %u\n",
-                                 dccp_role(sk), sk, len, option);
+                                 dccp_role(sk), sk, optlen, option);
                        return -EINVAL;
                }
-               opt_val = ntohl(get_unaligned((__be32 *)value));
+               opt_val = ntohl(get_unaligned((__be32 *)optval));
 
                if (option == TFRC_OPT_RECEIVE_RATE) {
-                       opt_recv->ccid3or_receive_rate = opt_val;
+                       /* Receive Rate is kept in units of 64 bytes/second */
+                       hc->tx_x_recv = opt_val;
+                       hc->tx_x_recv <<= 6;
+
                        ccid3_pr_debug("%s(%p), RECEIVE_RATE=%u\n",
                                       dccp_role(sk), sk, opt_val);
                } else {
-                       opt_recv->ccid3or_loss_event_rate = opt_val;
+                       /* Update the fixpoint Loss Event Rate fraction */
+                       hc->tx_p = tfrc_invert_loss_event_rate(opt_val);
+
                        ccid3_pr_debug("%s(%p), LOSS_EVENT_RATE=%u\n",
                                       dccp_role(sk), sk, opt_val);
                }
@@ -527,9 +512,7 @@ static void ccid3_hc_tx_exit(struct sock *sk)
 {
        struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
 
-       ccid3_hc_tx_set_state(sk, TFRC_SSTATE_TERM);
        sk_stop_timer(sk, &hc->tx_no_feedback_timer);
-
        tfrc_tx_hist_purge(&hc->tx_hist);
 }
 
@@ -588,7 +571,6 @@ static const char *ccid3_rx_state_name(enum ccid3_hc_rx_states state)
        static const char *const ccid3_rx_state_names[] = {
        [TFRC_RSTATE_NO_DATA] = "NO_DATA",
        [TFRC_RSTATE_DATA]    = "DATA",
-       [TFRC_RSTATE_TERM]    = "TERM",
        };
 
        return ccid3_rx_state_names[state];
@@ -614,14 +596,9 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk,
 {
        struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
-       ktime_t now;
+       ktime_t now = ktime_get_real();
        s64 delta = 0;
 
-       if (unlikely(hc->rx_state == TFRC_RSTATE_TERM))
-               return;
-
-       now = ktime_get_real();
-
        switch (fbtype) {
        case CCID3_FBACK_INITIAL:
                hc->rx_x_recv = 0;
@@ -825,8 +802,6 @@ static void ccid3_hc_rx_exit(struct sock *sk)
 {
        struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
 
-       ccid3_hc_rx_set_state(sk, TFRC_RSTATE_TERM);
-
        tfrc_rx_hist_purge(&hc->rx_hist);
        tfrc_lh_cleanup(&hc->rx_li_hist);
 }
@@ -851,8 +826,7 @@ static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len,
                        return -EINVAL;
                rx_info.tfrcrx_x_recv = hc->rx_x_recv;
                rx_info.tfrcrx_rtt    = hc->rx_rtt;
-               rx_info.tfrcrx_p      = hc->rx_pinv == 0 ? ~0U :
-                                          scaled_div(1, hc->rx_pinv);
+               rx_info.tfrcrx_p      = tfrc_invert_loss_event_rate(hc->rx_pinv);
                len = sizeof(rx_info);
                val = &rx_info;
                break;
index 9eb90b863abd5ae10e1105d15f302016a8366ff0..1a9933c29672bfa3d1e8396a33437a5712970b5d 100644 (file)
@@ -67,17 +67,11 @@ enum ccid3_options {
        TFRC_OPT_RECEIVE_RATE    = 194,
 };
 
-struct ccid3_options_received {
-       u32 ccid3or_loss_event_rate;
-       u32 ccid3or_receive_rate;
-};
-
 /* TFRC sender states */
 enum ccid3_hc_tx_states {
        TFRC_SSTATE_NO_SENT = 1,
        TFRC_SSTATE_NO_FBACK,
        TFRC_SSTATE_FBACK,
-       TFRC_SSTATE_TERM,
 };
 
 /**
@@ -98,7 +92,6 @@ enum ccid3_hc_tx_states {
  * @tx_t_ld:             Time last doubled during slow start
  * @tx_t_nom:            Nominal send time of next packet
  * @tx_hist:             Packet history
- * @tx_options_received:  Parsed set of retrieved options
  */
 struct ccid3_hc_tx_sock {
        u64                             tx_x;
@@ -116,7 +109,6 @@ struct ccid3_hc_tx_sock {
        ktime_t                         tx_t_ld;
        ktime_t                         tx_t_nom;
        struct tfrc_tx_hist_entry       *tx_hist;
-       struct ccid3_options_received   tx_options_received;
 };
 
 static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
@@ -130,7 +122,6 @@ static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk)
 enum ccid3_hc_rx_states {
        TFRC_RSTATE_NO_DATA = 1,
        TFRC_RSTATE_DATA,
-       TFRC_RSTATE_TERM    = 127,
 };
 
 /**
index 01bb48e96c2ed0b6955c50ee348817e1415f61fd..f8ee3f5497702c300c43c6529358c4dd5ee137f3 100644 (file)
@@ -57,6 +57,7 @@ static inline u32 tfrc_ewma(const u32 avg, const u32 newval, const u8 weight)
 
 extern u32  tfrc_calc_x(u16 s, u32 R, u32 p);
 extern u32  tfrc_calc_x_reverse_lookup(u32 fvalue);
+extern u32  tfrc_invert_loss_event_rate(u32 loss_event_rate);
 
 extern int  tfrc_tx_packet_history_init(void);
 extern void tfrc_tx_packet_history_exit(void);
index 22ca1cf0eb5503fe6ed2db69172771f0e207b182..a052a4377e262a6f2e1af8e354cfd649f006e343 100644 (file)
@@ -687,3 +687,17 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue)
        index = tfrc_binsearch(fvalue, 0);
        return (index + 1) * 1000000 / TFRC_CALC_X_ARRSIZE;
 }
+
+/**
+ * tfrc_invert_loss_event_rate  -  Compute p so that 10^6 corresponds to 100%
+ * When @loss_event_rate is large, there is a chance that p is truncated to 0.
+ * To avoid re-entering slow-start in that case, we set p = TFRC_SMALLEST_P > 0.
+ */
+u32 tfrc_invert_loss_event_rate(u32 loss_event_rate)
+{
+       if (loss_event_rate == UINT_MAX)                /* see RFC 4342, 8.5 */
+               return 0;
+       if (unlikely(loss_event_rate == 0))             /* map 1/0 into 100% */
+               return 1000000;
+       return max_t(u32, scaled_div(1, loss_event_rate), TFRC_SMALLEST_P);
+}
index bfda087bd90dd792f8190840878379d304152c1d..92718511eac5af1d1896196c2591f5621dd22d38 100644 (file)
@@ -96,18 +96,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                }
 
                /*
-                * CCID-Specific Options (from RFC 4340, sec. 10.3):
-                *
-                * Option numbers 128 through 191 are for options sent from the
-                * HC-Sender to the HC-Receiver; option numbers 192 through 255
-                * are for options sent from the HC-Receiver to the HC-Sender.
-                *
                 * CCID-specific options are ignored during connection setup, as
                 * negotiation may still be in progress (see RFC 4340, 10.3).
                 * The same applies to Ack Vectors, as these depend on the CCID.
-                *
                 */
-               if (dreq != NULL && (opt >= 128 ||
+               if (dreq != NULL && (opt >= DCCPO_MIN_RX_CCID_SPECIFIC ||
                    opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1))
                        goto ignore_option;
 
@@ -226,23 +219,15 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
                        dccp_pr_debug("%s rx opt: ELAPSED_TIME=%d\n",
                                      dccp_role(sk), elapsed_time);
                        break;
-               case 128 ... 191: {
-                       const u16 idx = value - options;
-
+               case DCCPO_MIN_RX_CCID_SPECIFIC ... DCCPO_MAX_RX_CCID_SPECIFIC:
                        if (ccid_hc_rx_parse_options(dp->dccps_hc_rx_ccid, sk,
-                                                    opt, len, idx,
-                                                    value) != 0)
+                                                    pkt_type, opt, value, len))
                                goto out_invalid_option;
-               }
                        break;
-               case 192 ... 255: {
-                       const u16 idx = value - options;
-
+               case DCCPO_MIN_TX_CCID_SPECIFIC ... DCCPO_MAX_TX_CCID_SPECIFIC:
                        if (ccid_hc_tx_parse_options(dp->dccps_hc_tx_ccid, sk,
-                                                    opt, len, idx,
-                                                    value) != 0)
+                                                    pkt_type, opt, value, len))
                                goto out_invalid_option;
-               }
                        break;
                default:
                        DCCP_CRIT("DCCP(%p): option %d(len=%d) not "