diff options
-rw-r--r-- | net/dccp/ccids/Makefile | 2 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.c | 155 | ||||
-rw-r--r-- | net/dccp/ccids/ccid3.h | 11 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.c | 144 | ||||
-rw-r--r-- | net/dccp/ccids/lib/loss_interval.h | 61 |
5 files changed, 234 insertions, 139 deletions
diff --git a/net/dccp/ccids/Makefile b/net/dccp/ccids/Makefile index 1c720131c5db..323b68f3b607 100644 --- a/net/dccp/ccids/Makefile +++ b/net/dccp/ccids/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o | 1 | obj-$(CONFIG_IP_DCCP_CCID3) += dccp_ccid3.o |
2 | 2 | ||
3 | dccp_ccid3-y := ccid3.o | 3 | dccp_ccid3-y := ccid3.o lib/loss_interval.o |
diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index cfd11234d8f9..7468928b83c6 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "../ccid.h" | 38 | #include "../ccid.h" |
39 | #include "../dccp.h" | 39 | #include "../dccp.h" |
40 | #include "../packet_history.h" | 40 | #include "../packet_history.h" |
41 | #include "lib/loss_interval.h" | ||
41 | #include "ccid3.h" | 42 | #include "ccid3.h" |
42 | 43 | ||
43 | /* | 44 | /* |
@@ -62,30 +63,7 @@ static int ccid3_debug; | |||
62 | 63 | ||
63 | static struct dccp_tx_hist *ccid3_tx_hist; | 64 | static struct dccp_tx_hist *ccid3_tx_hist; |
64 | static struct dccp_rx_hist *ccid3_rx_hist; | 65 | static struct dccp_rx_hist *ccid3_rx_hist; |
65 | 66 | static struct dccp_li_hist *ccid3_li_hist; | |
66 | static kmem_cache_t *ccid3_loss_interval_hist_slab __read_mostly; | ||
67 | |||
68 | static inline struct ccid3_loss_interval_hist_entry * | ||
69 | ccid3_loss_interval_hist_entry_new(const unsigned int __nocast prio) | ||
70 | { | ||
71 | return kmem_cache_alloc(ccid3_loss_interval_hist_slab, prio); | ||
72 | } | ||
73 | |||
74 | static inline void ccid3_loss_interval_hist_entry_delete(struct ccid3_loss_interval_hist_entry *entry) | ||
75 | { | ||
76 | if (entry != NULL) | ||
77 | kmem_cache_free(ccid3_loss_interval_hist_slab, entry); | ||
78 | } | ||
79 | |||
80 | static void ccid3_loss_interval_history_delete(struct list_head *hist) | ||
81 | { | ||
82 | struct ccid3_loss_interval_hist_entry *entry, *next; | ||
83 | |||
84 | list_for_each_entry_safe(entry, next, hist, ccid3lih_node) { | ||
85 | list_del_init(&entry->ccid3lih_node); | ||
86 | kmem_cache_free(ccid3_loss_interval_hist_slab, entry); | ||
87 | } | ||
88 | } | ||
89 | 67 | ||
90 | static int ccid3_init(struct sock *sk) | 68 | static int ccid3_init(struct sock *sk) |
91 | { | 69 | { |
@@ -1414,7 +1392,7 @@ trim_history: | |||
1414 | */ | 1392 | */ |
1415 | num_later = TFRC_RECV_NUM_LATE_LOSS + 1; | 1393 | num_later = TFRC_RECV_NUM_LATE_LOSS + 1; |
1416 | 1394 | ||
1417 | if (!list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) { | 1395 | if (!list_empty(&hcrx->ccid3hcrx_li_hist)) { |
1418 | list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, | 1396 | list_for_each_entry_safe(entry, next, &hcrx->ccid3hcrx_hist, |
1419 | dccphrx_node) { | 1397 | dccphrx_node) { |
1420 | if (num_later == 0) { | 1398 | if (num_later == 0) { |
@@ -1555,15 +1533,6 @@ static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb) | |||
1555 | &x_recv, sizeof(x_recv)); | 1533 | &x_recv, sizeof(x_recv)); |
1556 | } | 1534 | } |
1557 | 1535 | ||
1558 | /* Weights used to calculate loss event rate */ | ||
1559 | /* | ||
1560 | * These are integers as per section 8 of RFC3448. We can then divide by 4 * | ||
1561 | * when we use it. | ||
1562 | */ | ||
1563 | static const int ccid3_hc_rx_w[TFRC_RECV_IVAL_F_LENGTH] = { | ||
1564 | 4, 4, 4, 4, 3, 2, 1, 1, | ||
1565 | }; | ||
1566 | |||
1567 | /* | 1536 | /* |
1568 | * args: fvalue - function value to match | 1537 | * args: fvalue - function value to match |
1569 | * returns: p closest to that value | 1538 | * returns: p closest to that value |
@@ -1672,41 +1641,17 @@ static void ccid3_hc_rx_update_li(struct sock *sk, u64 seq_loss, u8 win_loss) | |||
1672 | { | 1641 | { |
1673 | struct dccp_sock *dp = dccp_sk(sk); | 1642 | struct dccp_sock *dp = dccp_sk(sk); |
1674 | struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; | 1643 | struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; |
1675 | struct ccid3_loss_interval_hist_entry *li_entry; | ||
1676 | 1644 | ||
1677 | if (seq_loss != DCCP_MAX_SEQNO + 1) { | 1645 | if (seq_loss != DCCP_MAX_SEQNO + 1 && |
1678 | ccid3_pr_debug("%s, sk=%p, seq_loss=%llu, win_loss=%u, " | 1646 | list_empty(&hcrx->ccid3hcrx_li_hist)) { |
1679 | "packet loss detected\n", | 1647 | struct dccp_li_hist_entry *li_tail; |
1680 | dccp_role(sk), sk, seq_loss, win_loss); | ||
1681 | |||
1682 | if (list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) { | ||
1683 | struct ccid3_loss_interval_hist_entry *li_tail = NULL; | ||
1684 | int i; | ||
1685 | |||
1686 | ccid3_pr_debug("%s, sk=%p, first loss event detected, " | ||
1687 | "creating history\n", | ||
1688 | dccp_role(sk), sk); | ||
1689 | for (i = 0; i <= TFRC_RECV_IVAL_F_LENGTH; ++i) { | ||
1690 | li_entry = ccid3_loss_interval_hist_entry_new(SLAB_ATOMIC); | ||
1691 | if (li_entry == NULL) { | ||
1692 | ccid3_loss_interval_history_delete(&hcrx->ccid3hcrx_loss_interval_hist); | ||
1693 | ccid3_pr_debug("%s, sk=%p, not enough " | ||
1694 | "mem for creating " | ||
1695 | "history\n", | ||
1696 | dccp_role(sk), sk); | ||
1697 | return; | ||
1698 | } | ||
1699 | if (li_tail == NULL) | ||
1700 | li_tail = li_entry; | ||
1701 | list_add(&li_entry->ccid3lih_node, | ||
1702 | &hcrx->ccid3hcrx_loss_interval_hist); | ||
1703 | } | ||
1704 | 1648 | ||
1705 | li_entry->ccid3lih_seqno = seq_loss; | 1649 | li_tail = dccp_li_hist_interval_new(ccid3_li_hist, |
1706 | li_entry->ccid3lih_win_count = win_loss; | 1650 | &hcrx->ccid3hcrx_li_hist, |
1707 | 1651 | seq_loss, win_loss); | |
1708 | li_tail->ccid3lih_interval = ccid3_hc_rx_calc_first_li(sk); | 1652 | if (li_tail == NULL) |
1709 | } | 1653 | return; |
1654 | li_tail->dccplih_interval = ccid3_hc_rx_calc_first_li(sk); | ||
1710 | } | 1655 | } |
1711 | /* FIXME: find end of interval */ | 1656 | /* FIXME: find end of interval */ |
1712 | } | 1657 | } |
@@ -1746,12 +1691,11 @@ static void ccid3_hc_rx_detect_loss(struct sock *sk) | |||
1746 | } | 1691 | } |
1747 | 1692 | ||
1748 | if (a_loss == NULL) { | 1693 | if (a_loss == NULL) { |
1749 | if (list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) { | 1694 | if (list_empty(&hcrx->ccid3hcrx_li_hist)) { |
1750 | /* no loss event have occured yet */ | 1695 | /* no loss event have occured yet */ |
1751 | ccid3_pr_debug("%s, sk=%p, TODO: find a lost data " | 1696 | LIMIT_NETDEBUG("%s: TODO: find a lost data packet by " |
1752 | "packet by comparing to initial " | 1697 | "comparing to initial seqno\n", |
1753 | "seqno\n", | 1698 | dccp_role(sk)); |
1754 | dccp_role(sk), sk); | ||
1755 | goto out_update_li; | 1699 | goto out_update_li; |
1756 | } else { | 1700 | } else { |
1757 | pr_info("%s: %s, sk=%p, ERROR! Less than 4 data " | 1701 | pr_info("%s: %s, sk=%p, ERROR! Less than 4 data " |
@@ -1799,48 +1743,6 @@ out_update_li: | |||
1799 | ccid3_hc_rx_update_li(sk, seq_loss, win_loss); | 1743 | ccid3_hc_rx_update_li(sk, seq_loss, win_loss); |
1800 | } | 1744 | } |
1801 | 1745 | ||
1802 | static u32 ccid3_hc_rx_calc_i_mean(struct sock *sk) | ||
1803 | { | ||
1804 | struct dccp_sock *dp = dccp_sk(sk); | ||
1805 | struct ccid3_hc_rx_sock *hcrx = dp->dccps_hc_rx_ccid_private; | ||
1806 | struct ccid3_loss_interval_hist_entry *li_entry, *li_next; | ||
1807 | int i = 0; | ||
1808 | u32 i_tot; | ||
1809 | u32 i_tot0 = 0; | ||
1810 | u32 i_tot1 = 0; | ||
1811 | u32 w_tot = 0; | ||
1812 | |||
1813 | list_for_each_entry_safe(li_entry, li_next, | ||
1814 | &hcrx->ccid3hcrx_loss_interval_hist, | ||
1815 | ccid3lih_node) { | ||
1816 | if (i < TFRC_RECV_IVAL_F_LENGTH) { | ||
1817 | i_tot0 += li_entry->ccid3lih_interval * ccid3_hc_rx_w[i]; | ||
1818 | w_tot += ccid3_hc_rx_w[i]; | ||
1819 | } | ||
1820 | |||
1821 | if (i != 0) | ||
1822 | i_tot1 += li_entry->ccid3lih_interval * ccid3_hc_rx_w[i - 1]; | ||
1823 | |||
1824 | if (++i > TFRC_RECV_IVAL_F_LENGTH) | ||
1825 | break; | ||
1826 | } | ||
1827 | |||
1828 | if (i != TFRC_RECV_IVAL_F_LENGTH) { | ||
1829 | pr_info("%s: %s, sk=%p, ERROR! Missing entry in " | ||
1830 | "interval history!\n", | ||
1831 | __FUNCTION__, dccp_role(sk), sk); | ||
1832 | return 0; | ||
1833 | } | ||
1834 | |||
1835 | i_tot = max(i_tot0, i_tot1); | ||
1836 | |||
1837 | /* FIXME: Why do we do this? -Ian McDonald */ | ||
1838 | if (i_tot * 4 < w_tot) | ||
1839 | i_tot = w_tot * 4; | ||
1840 | |||
1841 | return i_tot * 4 / w_tot; | ||
1842 | } | ||
1843 | |||
1844 | static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | 1746 | static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) |
1845 | { | 1747 | { |
1846 | struct dccp_sock *dp = dccp_sk(sk); | 1748 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -1939,9 +1841,9 @@ static void ccid3_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb) | |||
1939 | p_prev = hcrx->ccid3hcrx_p; | 1841 | p_prev = hcrx->ccid3hcrx_p; |
1940 | 1842 | ||
1941 | /* Calculate loss event rate */ | 1843 | /* Calculate loss event rate */ |
1942 | if (!list_empty(&hcrx->ccid3hcrx_loss_interval_hist)) | 1844 | if (!list_empty(&hcrx->ccid3hcrx_li_hist)) |
1943 | /* Scaling up by 1000000 as fixed decimal */ | 1845 | /* Scaling up by 1000000 as fixed decimal */ |
1944 | hcrx->ccid3hcrx_p = 1000000 / ccid3_hc_rx_calc_i_mean(sk); | 1846 | hcrx->ccid3hcrx_p = 1000000 / dccp_li_hist_calc_i_mean(&hcrx->ccid3hcrx_li_hist); |
1945 | 1847 | ||
1946 | if (hcrx->ccid3hcrx_p > p_prev) { | 1848 | if (hcrx->ccid3hcrx_p > p_prev) { |
1947 | ccid3_hc_rx_send_feedback(sk); | 1849 | ccid3_hc_rx_send_feedback(sk); |
@@ -1971,7 +1873,7 @@ static int ccid3_hc_rx_init(struct sock *sk) | |||
1971 | 1873 | ||
1972 | hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; | 1874 | hcrx->ccid3hcrx_state = TFRC_RSTATE_NO_DATA; |
1973 | INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); | 1875 | INIT_LIST_HEAD(&hcrx->ccid3hcrx_hist); |
1974 | INIT_LIST_HEAD(&hcrx->ccid3hcrx_loss_interval_hist); | 1876 | INIT_LIST_HEAD(&hcrx->ccid3hcrx_li_hist); |
1975 | /* | 1877 | /* |
1976 | * XXX this seems to be paranoid, need to think more about this, for | 1878 | * XXX this seems to be paranoid, need to think more about this, for |
1977 | * now start with something different than zero. -acme | 1879 | * now start with something different than zero. -acme |
@@ -1996,7 +1898,7 @@ static void ccid3_hc_rx_exit(struct sock *sk) | |||
1996 | dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); | 1898 | dccp_rx_hist_purge(ccid3_rx_hist, &hcrx->ccid3hcrx_hist); |
1997 | 1899 | ||
1998 | /* Empty loss interval history */ | 1900 | /* Empty loss interval history */ |
1999 | ccid3_loss_interval_history_delete(&hcrx->ccid3hcrx_loss_interval_hist); | 1901 | dccp_li_hist_purge(ccid3_li_hist, &hcrx->ccid3hcrx_li_hist); |
2000 | 1902 | ||
2001 | kfree(dp->dccps_hc_rx_ccid_private); | 1903 | kfree(dp->dccps_hc_rx_ccid_private); |
2002 | dp->dccps_hc_rx_ccid_private = NULL; | 1904 | dp->dccps_hc_rx_ccid_private = NULL; |
@@ -2063,11 +1965,8 @@ static __init int ccid3_module_init(void) | |||
2063 | if (ccid3_tx_hist == NULL) | 1965 | if (ccid3_tx_hist == NULL) |
2064 | goto out_free_rx; | 1966 | goto out_free_rx; |
2065 | 1967 | ||
2066 | ccid3_loss_interval_hist_slab = kmem_cache_create("li_hist_ccid3", | 1968 | ccid3_li_hist = dccp_li_hist_new("ccid3"); |
2067 | sizeof(struct ccid3_loss_interval_hist_entry), | 1969 | if (ccid3_li_hist == NULL) |
2068 | 0, SLAB_HWCACHE_ALIGN, | ||
2069 | NULL, NULL); | ||
2070 | if (ccid3_loss_interval_hist_slab == NULL) | ||
2071 | goto out_free_tx; | 1970 | goto out_free_tx; |
2072 | 1971 | ||
2073 | rc = ccid_register(&ccid3); | 1972 | rc = ccid_register(&ccid3); |
@@ -2077,8 +1976,8 @@ out: | |||
2077 | return rc; | 1976 | return rc; |
2078 | 1977 | ||
2079 | out_free_loss_interval_history: | 1978 | out_free_loss_interval_history: |
2080 | kmem_cache_destroy(ccid3_loss_interval_hist_slab); | 1979 | dccp_li_hist_delete(ccid3_li_hist); |
2081 | ccid3_loss_interval_hist_slab = NULL; | 1980 | ccid3_li_hist = NULL; |
2082 | out_free_tx: | 1981 | out_free_tx: |
2083 | dccp_tx_hist_delete(ccid3_tx_hist); | 1982 | dccp_tx_hist_delete(ccid3_tx_hist); |
2084 | ccid3_tx_hist = NULL; | 1983 | ccid3_tx_hist = NULL; |
@@ -2110,9 +2009,9 @@ static __exit void ccid3_module_exit(void) | |||
2110 | dccp_rx_hist_delete(ccid3_rx_hist); | 2009 | dccp_rx_hist_delete(ccid3_rx_hist); |
2111 | ccid3_rx_hist = NULL; | 2010 | ccid3_rx_hist = NULL; |
2112 | } | 2011 | } |
2113 | if (ccid3_loss_interval_hist_slab != NULL) { | 2012 | if (ccid3_li_hist != NULL) { |
2114 | kmem_cache_destroy(ccid3_loss_interval_hist_slab); | 2013 | dccp_li_hist_delete(ccid3_li_hist); |
2115 | ccid3_loss_interval_hist_slab = NULL; | 2014 | ccid3_li_hist = NULL; |
2116 | } | 2015 | } |
2117 | } | 2016 | } |
2118 | module_exit(ccid3_module_exit); | 2017 | module_exit(ccid3_module_exit); |
diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index f8965700bbe9..f68d0b4e31e9 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h | |||
@@ -59,8 +59,6 @@ | |||
59 | 59 | ||
60 | #define TFRC_SMALLEST_P 40 | 60 | #define TFRC_SMALLEST_P 40 |
61 | 61 | ||
62 | #define TFRC_RECV_IVAL_F_LENGTH 8 | ||
63 | |||
64 | /* Number of later packets received before one is considered lost */ | 62 | /* Number of later packets received before one is considered lost */ |
65 | #define TFRC_RECV_NUM_LATE_LOSS 3 | 63 | #define TFRC_RECV_NUM_LATE_LOSS 3 |
66 | 64 | ||
@@ -119,13 +117,6 @@ struct ccid3_hc_tx_sock { | |||
119 | struct ccid3_options_received ccid3hctx_options_received; | 117 | struct ccid3_options_received ccid3hctx_options_received; |
120 | }; | 118 | }; |
121 | 119 | ||
122 | struct ccid3_loss_interval_hist_entry { | ||
123 | struct list_head ccid3lih_node; | ||
124 | u64 ccid3lih_seqno:48, | ||
125 | ccid3lih_win_count:4; | ||
126 | u32 ccid3lih_interval; | ||
127 | }; | ||
128 | |||
129 | struct ccid3_hc_rx_sock { | 120 | struct ccid3_hc_rx_sock { |
130 | u64 ccid3hcrx_seqno_last_counter:48, | 121 | u64 ccid3hcrx_seqno_last_counter:48, |
131 | ccid3hcrx_state:8, | 122 | ccid3hcrx_state:8, |
@@ -136,7 +127,7 @@ struct ccid3_hc_rx_sock { | |||
136 | struct timeval ccid3hcrx_tstamp_last_feedback; | 127 | struct timeval ccid3hcrx_tstamp_last_feedback; |
137 | struct timeval ccid3hcrx_tstamp_last_ack; | 128 | struct timeval ccid3hcrx_tstamp_last_ack; |
138 | struct list_head ccid3hcrx_hist; | 129 | struct list_head ccid3hcrx_hist; |
139 | struct list_head ccid3hcrx_loss_interval_hist; | 130 | struct list_head ccid3hcrx_li_hist; |
140 | u16 ccid3hcrx_s; | 131 | u16 ccid3hcrx_s; |
141 | u32 ccid3hcrx_pinv; | 132 | u32 ccid3hcrx_pinv; |
142 | u32 ccid3hcrx_elapsed_time; | 133 | u32 ccid3hcrx_elapsed_time; |
diff --git a/net/dccp/ccids/lib/loss_interval.c b/net/dccp/ccids/lib/loss_interval.c new file mode 100644 index 000000000000..4c01a54143ad --- /dev/null +++ b/net/dccp/ccids/lib/loss_interval.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * net/dccp/ccids/lib/loss_interval.c | ||
3 | * | ||
4 | * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. | ||
5 | * Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz> | ||
6 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/module.h> | ||
16 | |||
17 | #include "loss_interval.h" | ||
18 | |||
19 | struct dccp_li_hist *dccp_li_hist_new(const char *name) | ||
20 | { | ||
21 | struct dccp_li_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC); | ||
22 | static const char dccp_li_hist_mask[] = "li_hist_%s"; | ||
23 | char *slab_name; | ||
24 | |||
25 | if (hist == NULL) | ||
26 | goto out; | ||
27 | |||
28 | slab_name = kmalloc(strlen(name) + sizeof(dccp_li_hist_mask) - 1, | ||
29 | GFP_ATOMIC); | ||
30 | if (slab_name == NULL) | ||
31 | goto out_free_hist; | ||
32 | |||
33 | sprintf(slab_name, dccp_li_hist_mask, name); | ||
34 | hist->dccplih_slab = kmem_cache_create(slab_name, | ||
35 | sizeof(struct dccp_li_hist_entry), | ||
36 | 0, SLAB_HWCACHE_ALIGN, | ||
37 | NULL, NULL); | ||
38 | if (hist->dccplih_slab == NULL) | ||
39 | goto out_free_slab_name; | ||
40 | out: | ||
41 | return hist; | ||
42 | out_free_slab_name: | ||
43 | kfree(slab_name); | ||
44 | out_free_hist: | ||
45 | kfree(hist); | ||
46 | hist = NULL; | ||
47 | goto out; | ||
48 | } | ||
49 | |||
50 | EXPORT_SYMBOL_GPL(dccp_li_hist_new); | ||
51 | |||
52 | void dccp_li_hist_delete(struct dccp_li_hist *hist) | ||
53 | { | ||
54 | const char* name = kmem_cache_name(hist->dccplih_slab); | ||
55 | |||
56 | kmem_cache_destroy(hist->dccplih_slab); | ||
57 | kfree(name); | ||
58 | kfree(hist); | ||
59 | } | ||
60 | |||
61 | EXPORT_SYMBOL_GPL(dccp_li_hist_delete); | ||
62 | |||
63 | void dccp_li_hist_purge(struct dccp_li_hist *hist, struct list_head *list) | ||
64 | { | ||
65 | struct dccp_li_hist_entry *entry, *next; | ||
66 | |||
67 | list_for_each_entry_safe(entry, next, list, dccplih_node) { | ||
68 | list_del_init(&entry->dccplih_node); | ||
69 | kmem_cache_free(hist->dccplih_slab, entry); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | EXPORT_SYMBOL_GPL(dccp_li_hist_purge); | ||
74 | |||
75 | /* Weights used to calculate loss event rate */ | ||
76 | /* | ||
77 | * These are integers as per section 8 of RFC3448. We can then divide by 4 * | ||
78 | * when we use it. | ||
79 | */ | ||
80 | static const int dccp_li_hist_w[DCCP_LI_HIST_IVAL_F_LENGTH] = { | ||
81 | 4, 4, 4, 4, 3, 2, 1, 1, | ||
82 | }; | ||
83 | |||
84 | u32 dccp_li_hist_calc_i_mean(struct list_head *list) | ||
85 | { | ||
86 | struct dccp_li_hist_entry *li_entry, *li_next; | ||
87 | int i = 0; | ||
88 | u32 i_tot; | ||
89 | u32 i_tot0 = 0; | ||
90 | u32 i_tot1 = 0; | ||
91 | u32 w_tot = 0; | ||
92 | |||
93 | list_for_each_entry_safe(li_entry, li_next, list, dccplih_node) { | ||
94 | if (i < DCCP_LI_HIST_IVAL_F_LENGTH) { | ||
95 | i_tot0 += li_entry->dccplih_interval * dccp_li_hist_w[i]; | ||
96 | w_tot += dccp_li_hist_w[i]; | ||
97 | } | ||
98 | |||
99 | if (i != 0) | ||
100 | i_tot1 += li_entry->dccplih_interval * dccp_li_hist_w[i - 1]; | ||
101 | |||
102 | if (++i > DCCP_LI_HIST_IVAL_F_LENGTH) | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | if (i != DCCP_LI_HIST_IVAL_F_LENGTH) | ||
107 | return 0; | ||
108 | |||
109 | i_tot = max(i_tot0, i_tot1); | ||
110 | |||
111 | /* FIXME: Why do we do this? -Ian McDonald */ | ||
112 | if (i_tot * 4 < w_tot) | ||
113 | i_tot = w_tot * 4; | ||
114 | |||
115 | return i_tot * 4 / w_tot; | ||
116 | } | ||
117 | |||
118 | EXPORT_SYMBOL_GPL(dccp_li_hist_calc_i_mean); | ||
119 | |||
120 | struct dccp_li_hist_entry *dccp_li_hist_interval_new(struct dccp_li_hist *hist, | ||
121 | struct list_head *list, | ||
122 | const u64 seq_loss, | ||
123 | const u8 win_loss) | ||
124 | { | ||
125 | struct dccp_li_hist_entry *tail = NULL, *entry; | ||
126 | int i; | ||
127 | |||
128 | for (i = 0; i <= DCCP_LI_HIST_IVAL_F_LENGTH; ++i) { | ||
129 | entry = dccp_li_hist_entry_new(hist, SLAB_ATOMIC); | ||
130 | if (entry == NULL) { | ||
131 | dccp_li_hist_purge(hist, list); | ||
132 | return NULL; | ||
133 | } | ||
134 | if (tail == NULL) | ||
135 | tail = entry; | ||
136 | list_add(&entry->dccplih_node, list); | ||
137 | } | ||
138 | |||
139 | entry->dccplih_seqno = seq_loss; | ||
140 | entry->dccplih_win_count = win_loss; | ||
141 | return tail; | ||
142 | } | ||
143 | |||
144 | EXPORT_SYMBOL_GPL(dccp_li_hist_interval_new); | ||
diff --git a/net/dccp/ccids/lib/loss_interval.h b/net/dccp/ccids/lib/loss_interval.h new file mode 100644 index 000000000000..13ad47ba1420 --- /dev/null +++ b/net/dccp/ccids/lib/loss_interval.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef _DCCP_LI_HIST_ | ||
2 | #define _DCCP_LI_HIST_ | ||
3 | /* | ||
4 | * net/dccp/ccids/lib/loss_interval.h | ||
5 | * | ||
6 | * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. | ||
7 | * Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz> | ||
8 | * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the Free | ||
12 | * Software Foundation; either version 2 of the License, or (at your option) | ||
13 | * any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/time.h> | ||
20 | |||
21 | #define DCCP_LI_HIST_IVAL_F_LENGTH 8 | ||
22 | |||
23 | struct dccp_li_hist { | ||
24 | kmem_cache_t *dccplih_slab; | ||
25 | }; | ||
26 | |||
27 | extern struct dccp_li_hist *dccp_li_hist_new(const char *name); | ||
28 | extern void dccp_li_hist_delete(struct dccp_li_hist *hist); | ||
29 | |||
30 | struct dccp_li_hist_entry { | ||
31 | struct list_head dccplih_node; | ||
32 | u64 dccplih_seqno:48, | ||
33 | dccplih_win_count:4; | ||
34 | u32 dccplih_interval; | ||
35 | }; | ||
36 | |||
37 | static inline struct dccp_li_hist_entry * | ||
38 | dccp_li_hist_entry_new(struct dccp_li_hist *hist, | ||
39 | const unsigned int __nocast prio) | ||
40 | { | ||
41 | return kmem_cache_alloc(hist->dccplih_slab, prio); | ||
42 | } | ||
43 | |||
44 | static inline void dccp_li_hist_entry_delete(struct dccp_li_hist *hist, | ||
45 | struct dccp_li_hist_entry *entry) | ||
46 | { | ||
47 | if (entry != NULL) | ||
48 | kmem_cache_free(hist->dccplih_slab, entry); | ||
49 | } | ||
50 | |||
51 | extern void dccp_li_hist_purge(struct dccp_li_hist *hist, | ||
52 | struct list_head *list); | ||
53 | |||
54 | extern u32 dccp_li_hist_calc_i_mean(struct list_head *list); | ||
55 | |||
56 | extern struct dccp_li_hist_entry * | ||
57 | dccp_li_hist_interval_new(struct dccp_li_hist *hist, | ||
58 | struct list_head *list, | ||
59 | const u64 seq_loss, | ||
60 | const u8 win_loss); | ||
61 | #endif /* _DCCP_LI_HIST_ */ | ||