tcp-linux.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:28k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* -*- Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
  2. /*
  3.  * Copyright (c) 1990, 1997 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that the above copyright notice and this paragraph are
  8.  * duplicated in all such forms and that any documentation,
  9.  * advertising materials, and other materials related to such
  10.  * distribution and use acknowledge that the software was developed
  11.  * by the University of California, Lawrence Berkeley Laboratory,
  12.  * Berkeley, CA.  The name of the University may not be used to
  13.  * endorse or promote products derived from this software without
  14.  * specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19. /* 
  20.  * TCP-Linux module for NS2 
  21.  *
  22.  * May 2006
  23.  *
  24.  * Author: Xiaoliang (David) Wei  (DavidWei@acm.org)
  25.  *
  26.  * NetLab, the California Institute of Technology 
  27.  * http://netlab.caltech.edu
  28.  *
  29.  * Module: tcp-linux.cc 
  30.  *      This is the main NS-2 module for TCP-Linux.
  31.  *
  32.  *
  33.  * See a mini-tutorial about TCP-Linux at: http://netlab.caltech.edu/projects/ns2tcplinux/
  34.  *
  35.  */
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <sys/types.h>
  39. #include "ip.h"
  40. #include "tcp.h"
  41. #include "flags.h"
  42. #include "random.h"
  43. #include "tcp-linux.h"
  44. #include "template.h"
  45. CongestionControlManager cong_ops_manager;
  46. CongestionControlManager::CongestionControlManager() {
  47. scan();
  48. };
  49. void CongestionControlManager::scan() {
  50. struct tcp_congestion_ops *e;
  51. num_ = 1;
  52. list_for_each_entry_rcu(e, &ns_tcp_cong_list, list) {
  53. num_++;
  54. };
  55. ops_list = new struct tcp_congestion_ops*[num_];
  56. ops_list[0] = &tcp_reno;
  57. int i=1;
  58. list_for_each_entry_rcu(e, &tcp_cong_list, list) {
  59. ops_list[i] = e;
  60. i++;
  61. }
  62. cc_list_changed = 0;
  63. //printf("congestion control algorithm initializedn");
  64. };
  65. struct tcp_congestion_ops* CongestionControlManager::get_ops(const char* name) {
  66. if (cc_list_changed) scan();
  67. for (int i=0; i< num_; i++) {
  68. if (strcmp(name, ops_list[i]->name)==0)
  69. return ops_list[i];
  70. }
  71. return 0;
  72. };
  73. void CongestionControlManager::dump() {
  74. printf("List of cc (total %d) :", num_);
  75. for (int i=0; i< num_; i++) {
  76. printf(" %s", ops_list[i]->name);
  77. }
  78. printf("n");
  79. };
  80. static class LinuxTcpClass : public TclClass {
  81. public:
  82. LinuxTcpClass() : TclClass("Agent/TCP/Linux") {}
  83. TclObject* create(int, const char*const*) {
  84. return (new LinuxTcpAgent());
  85. }
  86. } class_linux;
  87. LinuxTcpAgent::LinuxTcpAgent() :
  88. initialized_(false),
  89. next_pkts_in_flight_(0)
  90. {
  91. bind("next_pkts_in_flight_", &next_pkts_in_flight_);
  92. scb_ = new ScoreBoard1();
  93. linux_.icsk_ca_ops = NULL;
  94.         linux_.snd_cwnd_stamp = 0;
  95. linux_.icsk_ca_state = TCP_CA_Open;
  96. linux_.snd_cwnd = 2;
  97. linux_.snd_cwnd_cnt = 0;
  98. linux_.bytes_acked = 0;
  99. //load_to_linux_once();
  100. // scb_->test();
  101. }
  102. LinuxTcpAgent::~LinuxTcpAgent(){
  103. delete scb_;
  104. remove_congestion_control();
  105. }
  106. int LinuxTcpAgent::window() 
  107. {
  108. return (linux_.snd_cwnd);
  109. }
  110. double LinuxTcpAgent::windowd()
  111. {
  112. return (linux_.snd_cwnd);
  113. //+ min((double)linux_.snd_cwnd_cnt/(double)linux_.snd_cwnd, 1));
  114. }
  115. void LinuxTcpAgent::reset()
  116. {
  117. scb_->ClearScoreBoard();
  118. linux_.icsk_ca_state = TCP_CA_Open;
  119. linux_.snd_cwnd_stamp = 0;
  120. linux_.snd_cwnd = 2;
  121. linux_.bytes_acked = 0;
  122. initialized_ = false;
  123. TcpAgent::reset();
  124. load_to_linux_once();
  125. load_to_linux();
  126. }
  127. ////////////////// Ack processing part //////////////////////////////
  128. unsigned char LinuxTcpAgent::ack_processing(Packet* pkt, unsigned char flag)
  129. {
  130. hdr_tcp *tcph = hdr_tcp::access(pkt);
  131. //update sequence numbers
  132. if (flag&FLAG_DATA_ACKED) {
  133. highest_ack_ = tcph->seqno();
  134. linux_.snd_una = (highest_ack_+1)*linux_.mss_cache;
  135. maxseq_ = max(maxseq_, highest_ack_);
  136. if (t_seqno_ < highest_ack_ + 1) {
  137. t_seqno_ = highest_ack_ + 1;
  138. linux_.snd_nxt = t_seqno_*linux_.mss_cache;
  139. }
  140. return flag;
  141. } else {
  142. return flag | FLAG_UNSURE_TSTAMP;
  143. };
  144. }
  145. void LinuxTcpAgent::time_processing(Packet* pkt, unsigned char flag, s32* seq_urtt_p/*, s32* seq_usrtt_p*/)
  146. {
  147.         hdr_tcp *tcph = hdr_tcp::access(pkt);
  148. #define renew_timer {if (t_seqno_ > highest_ack_|| highest_ack_< maxseq_ || linux_.snd_cwnd < 1) set_rtx_timer(); else cancel_rtx_timer();}
  149. if (!timerfix_) renew_timer;
  150. //update time:
  151. double now = Scheduler::instance().clock();
  152. ts_peer_ = tcph->ts();          //record timestamp for echoing
  153. /* 
  154.  * Update RTT only if it's OK to do so from info in the flags header.
  155.  * This is needed for protocols in which intermediate agents
  156.  * in the network intersperse acks (e.g., ack-reconstructors) for
  157.  * various reasons (without violating e2e semantics).
  158.  */
  159. hdr_flags *fh = hdr_flags::access(pkt);
  160. linux_.rx_opt.saw_tstamp = 0;
  161. if (!fh->no_ts_) {
  162. if (ts_option_) {
  163. ts_echo_ = tcph->ts_echo();
  164. linux_.rx_opt.saw_tstamp = 1;
  165. linux_.rx_opt.rcv_tsecr = (__u32) (round(ts_echo_*JIFFY_RATIO));
  166. linux_.rx_opt.rcv_tsval = (__u32) (round(tcph->ts()*JIFFY_RATIO));
  167. if (flag & FLAG_UNSURE_TSTAMP)
  168. // we are not sure which packet generates this ack
  169. rtt_update(now - tcph->ts_echo(), 0);
  170. else
  171. //we are sure this packet generates this ack
  172. rtt_update(now - tcph->ts_echo(), tcph->seqno());
  173. (*seq_urtt_p) = (s32)(round((now - tcph->ts_echo())*JIFFY_RATIO));
  174. /*(*seq_usrtt_p) = (s32)(round((now - tcph->ts_echo())*US_RATIO));*/
  175. if (ts_resetRTO_) { 
  176. t_backoff_ = 1;
  177. if (!ect_ || !ecn_backoff_ || !hdr_flags::access(pkt)->ecnecho()) { 
  178. // From Andrei Gurtov
  179. /* 
  180.  * Don't end backoff if still in ECN-Echo with
  181.    * a congestion window of 1 packet. 
  182.  */
  183. ecn_backoff_ = 0;
  184. }
  185. }
  186. }
  187. }
  188. if (rtt_active_ && tcph->seqno() >= rtt_seq_) {
  189. if (!ect_ || !ecn_backoff_ || 
  190. !hdr_flags::access(pkt)->ecnecho()) {
  191. /* 
  192.  * Don't end backoff if still in ECN-Echo with
  193.    * a congestion window of 1 packet. 
  194.  */
  195. t_backoff_ = 1;
  196. ecn_backoff_ = 0;
  197. }
  198. rtt_active_ = 0;
  199. if (!linux_.rx_opt.saw_tstamp)
  200. rtt_update(now - rtt_ts_, 0);
  201. }
  202. if (timerfix_) renew_timer;
  203. /* update average window */
  204. awnd_ *= 1.0 - wnd_th_;
  205. awnd_ += wnd_th_ * cwnd_;
  206. /* if the connection is done, call finish() */
  207. if ((highest_ack_ >= curseq_-1) && !closed_) {
  208. closed_ = 1;
  209. finish();
  210. }
  211. };
  212. void LinuxTcpAgent::rtt_update(double tao, unsigned long pkt_seq_no)
  213. {
  214. double now = Scheduler::instance().clock();
  215. if (ts_option_)
  216. t_rtt_ = int(tao /tcp_tick_ + 0.5);
  217. else {
  218. double sendtime = now - tao;
  219. sendtime += boot_time_;
  220. double tickoff = fmod(sendtime, tcp_tick_);
  221. t_rtt_ = int((tao + tickoff) / tcp_tick_);
  222. }
  223. /*Record microsecond timestamp*/
  224. if ((linux_.icsk_ca_ops) && (linux_.icsk_ca_ops->rtt_sample)) {
  225. if ( bugfix_ts_ && pkt_seq_no && tss ) {
  226. //if we use the tss value when we have the timestamp
  227. //unsigned long a = (unsigned long)(round((now-tss[pkt_seq_no % tss_size_])*US_RATIO));
  228. //unsigned long ha = highest_ack_;
  229. //if (a < 100)
  230. //printf("%lf (%p): RTT=%lu, seq:%lu, highest_ack:%lu tss_size: %lu timesamp:%lfn", now, this, a, pkt_seq_no, ha, tss_size_, tss[pkt_seq_no % tss_size_]);
  231. linux_.icsk_ca_ops->rtt_sample(&linux_, (unsigned long)(round((now-tss[pkt_seq_no % tss_size_])*US_RATIO)));
  232. } else { 
  233. //otherwise, use an approximation
  234. linux_.icsk_ca_ops->rtt_sample(&linux_, (unsigned long)(round(tao*US_RATIO)));
  235. }
  236. }
  237. if (t_rtt_ < 1)
  238. t_rtt_ = 1;
  239. //
  240. // t_srtt_ has 3 bits to the right of the binary point
  241. // t_rttvar_ has 2
  242.         // Thus "t_srtt_ >> T_SRTT_BITS" is the actual srtt, 
  243.    //   and "t_srtt_" is 8*srtt.
  244. // Similarly, "t_rttvar_ >> T_RTTVAR_BITS" is the actual rttvar,
  245. //   and "t_rttvar_" is 4*rttvar.
  246. //
  247.         if (t_srtt_ != 0) {
  248. register short delta;
  249. delta = t_rtt_ - (t_srtt_ >> T_SRTT_BITS); // d = (m - a0)
  250. if ((t_srtt_ += delta) <= 0) // a1 = 7/8 a0 + 1/8 m
  251. t_srtt_ = 1;
  252. if (delta < 0) {
  253. delta = -delta;
  254. delta -= (t_rttvar_ >> T_RTTVAR_BITS);
  255. if (delta>0)
  256. delta >>= T_SRTT_BITS;
  257. } else 
  258. delta -= (t_rttvar_ >> T_RTTVAR_BITS);
  259. t_rttvar_ += delta;
  260. // if ((t_rttvar_ += delta) <= 0) // var1 = 3/4 var0 + 1/4 |d|
  261. // t_rttvar_ = 1;
  262. } else {
  263. t_srtt_ = t_rtt_ << T_SRTT_BITS; // srtt = rtt
  264. t_rttvar_ = t_rtt_ << (T_RTTVAR_BITS-1); // rttvar = rtt / 2
  265. }
  266. //
  267. // Current retransmit value is 
  268. //    (unscaled) smoothed round trip estimate
  269. //    plus 2^rttvar_exp_ times (unscaled) rttvar. 
  270. //
  271. t_rtxcur_ = (((t_rttvar_ << (rttvar_exp_ + (T_SRTT_BITS - T_RTTVAR_BITS))) +
  272. t_srtt_)  >> T_SRTT_BITS ) * tcp_tick_;
  273. linux_.srtt = t_srtt_;
  274. return;
  275. }
  276. void LinuxTcpAgent::recv(Packet *pkt, Handler*)
  277. //equivalence to tcp_ack
  278. {
  279. hdr_tcp *tcph = hdr_tcp::access(pkt);
  280. struct sock* sk = &linux_;
  281. u32 prior_snd_una = highest_ack_+1;
  282. u32 ack = tcph->seqno()+1; //in linux, the concept of unack is one packet ahead (first non-acked)
  283. u32 prior_in_flight;
  284. s32 seq_rtt;
  285. unsigned char flag=0;
  286. tcp_time_stamp = (unsigned long) (trunc(Scheduler::instance().clock() * JIFFY_RATIO)); 
  287. ktime_get_real = (s64)trunc(Scheduler::instance().clock()*1000000000);
  288. #ifdef notdef
  289. if (pkt->type_ != PT_ACK) {
  290. Tcl::instance().evalf("%s error "received non-ack"",
  291.       name());
  292. Packet::free(pkt);
  293. return;
  294. }
  295. #endif
  296. ++nackpack_;
  297. if (ack > (unsigned long)t_seqno_) return;  // uninteresting_ack
  298. if (ack < prior_snd_una) return; // old_ack; only worth for D-SACK. but let's pass it.
  299. DEBUG(5, "received an ack packet %lun", ack);
  300. if (linux_.icsk_ca_ops) {
  301. //This has to be done before the first call to linux_.icsk_ca_ops.
  302. paramManager.load_local();
  303. //After this call, all return must be done after a paramManager.restore_default, or save_to_linux (which inclues restore_default).
  304. };
  305. if (hdr_flags::access(pkt)->ecnecho() && ecn_ && (ack>1)) {
  306. //ecn(tcph->seqno());
  307. flag |= FLAG_ECE; //ECN
  308. }
  309. prior_in_flight = packets_in_flight();
  310. if (ack>prior_snd_una) {
  311. linux_.bytes_acked += (ack - prior_snd_una)*linux_.mss_cache;
  312. flag |= (FLAG_DATA_ACKED);
  313. };
  314. flag |= ack_processing(pkt, flag);
  315. DEBUG(5, "ack_processed prior_snd_una=%lu ack=%lun", prior_snd_una, ack);
  316. if ((tcph->sa_length()> 0) || (FLAG_DATA_ACKED && (!scb_->IsEmpty()))) {
  317. flag |= scb_->UpdateScoreBoard(highest_ack_, tcph);
  318. };
  319. DEBUG(5, "sack processed sack len=%d n", tcph->sa_length());
  320. time_processing(pkt, flag, &seq_rtt);
  321. DEBUG(5, "time processedn");
  322. if (linux_.icsk_ca_ops) {
  323. if ((!initialized_)) {
  324. if  (linux_.icsk_ca_ops->init)
  325. linux_.icsk_ca_ops->init(&linux_);
  326. initialized_ = true;
  327. }
  328. if ((flag & FLAG_NOT_DUP) && (linux_.icsk_ca_ops->pkts_acked)){
  329. ktime_t last_ackt;
  330. if ((flag & FLAG_UNSURE_TSTAMP) || (!bugfix_ts_)) {
  331. last_ackt = 0;
  332. } else {
  333.         double then = tss[tcph->seqno() % tss_size_];
  334. last_ackt = (s64)trunc(then*1000000000);
  335. };
  336. linux_.icsk_ca_ops->pkts_acked(sk, ack - prior_snd_una, last_ackt);
  337. }
  338. if ((linux_.icsk_ca_state==TCP_CA_Open)&& (!(flag&FLAG_CA_ALERT)) && (flag&FLAG_NOT_DUP)) {
  339. tcp_ca_event(CA_EVENT_FAST_ACK);
  340. }
  341. else {
  342. tcp_ca_event(CA_EVENT_SLOW_ACK);
  343. }
  344. }
  345. //  if (tp->frto_counter) tcp_process_frto(sk, prior_snd_una); //We haven't done FRTO yet.
  346. #define tcp_ack_is_dubious(flag) (!(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) || linux_.icsk_ca_state != TCP_CA_Open)
  347. #define tcp_may_raise_cwnd(flag) (!(flag & FLAG_ECE) || linux_.snd_cwnd < linux_.snd_ssthresh) && 
  348. !((1 << linux_.icsk_ca_state) & (TCPF_CA_Recovery | TCPF_CA_CWR))
  349. #define tcp_cong_avoid(ack, rtt, in_flight, good) 
  350. {
  351. if (linux_.icsk_ca_ops) {
  352. linux_.icsk_ca_ops->cong_avoid(sk, ack*linux_.mss_cache, rtt, in_flight, good);
  353. } else {
  354. opencwnd();
  355. load_to_linux();
  356. }
  357. touch_cwnd();
  358. }
  359. DEBUG(5, "Event processedn");
  360. if (tcp_ack_is_dubious(flag)){
  361. if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(flag))
  362. tcp_cong_avoid(ack, seq_rtt, prior_in_flight, 0);
  363. DEBUG(5, "dubious track cc finishedn");
  364. tcp_fastretrans_alert(flag);
  365. } else {
  366. if ((flag & FLAG_DATA_ACKED)) {
  367. prev_highest_ack_ = highest_ack_ ;
  368. tcp_cong_avoid(ack, seq_rtt, prior_in_flight, 1);
  369. }
  370. };
  371. DEBUG(5, "cc all finishedn");
  372. if (linux_.icsk_ca_ops) {
  373. save_from_linux();
  374. paramManager.restore_default();
  375. };
  376. send_much(FALSE, 0, maxburst_); //anytime we can do send_much by checking it.
  377. DEBUG(5, "data sentn");
  378. Packet::free(pkt);
  379. #ifdef notyet
  380. if (trace_)
  381. plot();
  382. #endif
  383. }
  384. //////////////////////////////  Congestion Control part ////////////////////////////
  385. void LinuxTcpAgent::touch_cwnd() {
  386. linux_.snd_cwnd_stamp = tcp_time_stamp; /* we touch the congestion window in this function */
  387. }
  388. void LinuxTcpAgent::tcp_moderate_cwnd()
  389. {
  390. linux_.snd_cwnd = min((int)linux_.snd_cwnd, packets_in_flight()+ tcp_max_burst); //max
  391. touch_cwnd();
  392. }
  393. void LinuxTcpAgent::tcp_fastretrans_alert(unsigned char flag)
  394. {
  395. struct inet_connection_sock *icsk = &linux_;
  396. // We don't have tcp_mark_head_lost yet
  397. /* E. Check state exit conditions. State can be terminated
  398.  *    when high_seq is ACKed. */
  399. if (icsk->icsk_ca_state == TCP_CA_Open) {
  400. //no need to exit unless frto.
  401. } else {
  402. if (highest_ack_ >= recover_) {
  403. DEBUG(5,"clear scoread boardn");
  404. scb_->ClearScoreBoard();
  405. if (linux_.icsk_ca_ops == NULL) load_to_linux();
  406. if (linux_.snd_cwnd < linux_.snd_ssthresh)
  407. {
  408. linux_.snd_cwnd = linux_.snd_ssthresh;
  409. tcp_moderate_cwnd();
  410. }
  411. tcp_set_ca_state(TCP_CA_Open);
  412. next_pkts_in_flight_ = 0; //stop rate halving
  413. return;
  414. }
  415. }
  416. DEBUG(5, "before step F: %dn", linux_.icsk_ca_state);
  417. /* F. Process state. */
  418. switch (linux_.icsk_ca_state) {
  419. case TCP_CA_Recovery: break;
  420. case TCP_CA_Loss:
  421. //let it through
  422. default:
  423. //TCP_CA_Open and have loss or ECE
  424. if (flag&(FLAG_DATA_LOST | FLAG_ECE)) {
  425. recover_ = maxseq_;
  426. last_cwnd_action_ = CWND_ACTION_DUPACK;
  427.         touch_cwnd();
  428. next_pkts_in_flight_ = linux_.snd_cwnd; //we do rate halving
  429.         if (linux_.icsk_ca_ops==NULL) {
  430.                  slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_HALF);
  431. load_to_linux();
  432.          } else {
  433. //ok this is the linux part
  434. DEBUG(5, "check ssthreshn");
  435. linux_.snd_ssthresh = icsk->icsk_ca_ops->ssthresh(&linux_);
  436. linux_.snd_cwnd_cnt = 0;
  437. linux_.bytes_acked = 0;
  438. DEBUG(5, "check min_cwnd %pn", icsk->icsk_ca_ops->min_cwnd);
  439. if (icsk->icsk_ca_ops->min_cwnd)
  440. linux_.snd_cwnd = icsk->icsk_ca_ops->min_cwnd(&linux_);
  441. else
  442. linux_.snd_cwnd = linux_.snd_ssthresh;
  443. ncwndcuts_++;
  444. cong_action_ = TRUE;
  445. // Linux uses a CWR process to halve rate, we have a simpler one.
  446. }
  447. if (flag & FLAG_ECE) ++necnresponses_;
  448. tcp_set_ca_state(TCP_CA_Recovery);
  449. }
  450. }
  451. }
  452. void LinuxTcpAgent::enter_loss() 
  453. {
  454. paramManager.load_local();
  455. touch_cwnd();
  456. if (linux_.icsk_ca_ops==NULL) {
  457. slowdown(CLOSE_SSTHRESH_HALF|CLOSE_CWND_RESTART);
  458. load_to_linux();
  459. } else {
  460. //ok this is the linux part
  461. // if (icsk->icsk_ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
  462. //     (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) {
  463. //tp->prior_ssthresh = tcp_current_ssthresh(sk);
  464. // icsk->icsk_retransmits: this is the # of unrecovered loss. in our case, all the loss are unrecovered.
  465. // if (linux_icsk_ca_state <= TCP_CA_Disorder || (highest_ack_+1) == recover_ || linux_icsk_ca_state== TCP_CA_LOSS) {
  466. linux_.snd_ssthresh = linux_.icsk_ca_ops->ssthresh(&linux_);
  467. tcp_ca_event(CA_EVENT_LOSS);
  468. linux_.snd_cwnd = 1;
  469. linux_.snd_cwnd_cnt = 0;
  470. linux_.bytes_acked = 0;
  471. //We don't have undo yet, otherwise, we should have:
  472. //tp->undo_marker = tp->snd_una;
  473. //We don't have reording yet, otherwise, we should have:
  474. //tp->reordering = min_t(unsigned int, tp->reordering, sysctl_tcp_reordering);
  475. //tp->high_seq = tp->snd_nxt;
  476. //We don't have ECN yet, otherwise, we should have: 
  477. //TCP_ECN_queue_cwr(tp);
  478. ncwndcuts_++;
  479. cong_action_ = TRUE;
  480. }
  481. recover_ = maxseq_;
  482. tcp_set_ca_state(TCP_CA_Loss); 
  483. //scb_->ClearScoreBoard();
  484. scb_->MarkLoss(highest_ack_+1, t_seqno_);
  485. //In Linux, we don't clear scoreboard in timeout, unless it's SACK Renege. We don't consider SACK Renege here.
  486. paramManager.restore_default();
  487. }
  488. void LinuxTcpAgent::timeout(int tno)
  489. {
  490. if (tno == TCP_TIMER_RTX) {
  491. if (highest_ack_ == maxseq_ && !slow_start_restart_) {
  492. /*
  493.  * TCP option:
  494.  * If no outstanding data, then don't do anything.
  495.  */
  496. return;
  497. };
  498. last_cwnd_action_ = CWND_ACTION_TIMEOUT;
  499. /* if there is no outstanding data, don't cut down ssthresh_ */
  500. if (highest_ack_ == maxseq_ && restart_bugfix_) {
  501. if (linux_.icsk_ca_ops) save_from_linux();
  502. slowdown(CLOSE_CWND_INIT);
  503. load_to_linux();
  504. } else {
  505. // close down to 1 segment
  506. enter_loss();
  507. ++nrexmit_;
  508. };
  509. /* if there is no outstanding data, don't back off rtx timer */
  510. if (highest_ack_ == maxseq_)
  511. reset_rtx_timer(TCP_REASON_TIMEOUT,0);
  512. else
  513. reset_rtx_timer(TCP_REASON_TIMEOUT,1);
  514. next_pkts_in_flight_ = 0;
  515. linux_.bytes_acked = 0;
  516. save_from_linux();
  517. send_much(0, TCP_REASON_TIMEOUT);
  518. } else {
  519. /* we do not know what it is */
  520. if (linux_.icsk_ca_ops) save_from_linux();
  521. TcpAgent::timeout(tno);
  522. load_to_linux();
  523. };
  524. }
  525. ///////////////////////////   Sending control part ///////////////////
  526. int LinuxTcpAgent::packets_in_flight()
  527. {
  528. return (scb_->packets_in_flight(highest_ack_+1, t_seqno_));
  529. }
  530. bool LinuxTcpAgent::is_congestion() 
  531. {
  532. return ( packets_in_flight() >= (int)linux_.snd_cwnd);
  533. }
  534. void LinuxTcpAgent::send_much(int force, int reason, int maxburst)
  535. {
  536. register int found, npacket = 0;
  537. send_idle_helper();
  538. int win = window();
  539. int xmit_seqno;
  540. if (!force && delsnd_timer_.status() == TIMER_PENDING)
  541. return;
  542. /* 
  543.  * If TCP_TIMER_BURSTSND is pending, cancel it. The timer is
  544.  * set again, if necessary, after the maxburst pakts have been
  545.  * sent out.
  546. */
  547. if (burstsnd_timer_.status() == TIMER_PENDING)
  548. burstsnd_timer_.cancel();
  549. found = 1;
  550. /*
  551. * as long as the pipe is open and there is app data to send...
  552. */
  553. next_pkts_in_flight_ = min(next_pkts_in_flight_, packets_in_flight()+1);
  554. while ( packets_in_flight() < max(win, next_pkts_in_flight_) ) {
  555. if (overhead_ == 0 || force) {
  556. found = 0;
  557. xmit_seqno = scb_->GetNextRetran ();
  558. if (xmit_seqno == -1) {  // no retransmissions to send
  559. /* 
  560.  * if there is no more application data to send,
  561.  * do nothing
  562.  */
  563. if (t_seqno_ >= curseq_) 
  564. return;
  565. found = 1;
  566. xmit_seqno = t_seqno_++;
  567. } else {
  568. found = 1;
  569. DEBUG(5, "%lf (%p) : Retran %dn", Scheduler::instance().clock(), this, xmit_seqno);
  570. scb_->MarkRetran (xmit_seqno, t_seqno_);
  571. win = window();
  572. }
  573. if (found) {
  574. output(xmit_seqno, reason);
  575. next_pkts_in_flight_ = min( next_pkts_in_flight_, max(packets_in_flight()-1,1));
  576. if (t_seqno_ <= xmit_seqno) {
  577. printf("Hit a strange case 2.n");
  578. t_seqno_ = xmit_seqno + 1;
  579. }
  580. linux_.snd_nxt = t_seqno_*linux_.mss_cache;
  581. npacket++;
  582. }
  583. } else if (!(delsnd_timer_.status() == TIMER_PENDING)) {
  584. /*
  585.  * Set a delayed send timeout.
  586.  */
  587. delsnd_timer_.resched(Random::uniform(overhead_));
  588. return;
  589. }
  590. if (maxburst && npacket >= maxburst)
  591. break;
  592. } /* while */
  593. /* call helper function */
  594. send_helper(maxburst);
  595. }
  596. ////////////////////   Linux Module control part /////////////////////////////
  597. void LinuxTcpAgent::load_to_linux()
  598. {
  599. //TODO
  600. linux_.snd_ssthresh = (int)ssthresh_;
  601. if ((next_pkts_in_flight_ > (int)linux_.snd_cwnd) && (cwnd_ >= (int)linux_.snd_cwnd)) {
  602. //We are in the process of rate-halving and the traditional ns-2 does not ask for further reduction
  603. next_pkts_in_flight_ = (int)(trunc(cwnd_));
  604. } else {
  605. //We are not in the process of rate-halving -- safe to load
  606. linux_.snd_cwnd = (int)(trunc(cwnd_));
  607. //linux_.snd_cwnd_cnt = (int) ((cwnd_ - (double)linux_.snd_cwnd)* (double)linux_.snd_cwnd);
  608. }
  609. //read only:
  610. linux_.snd_cwnd_clamp = (int) wnd_;
  611. //read only for linux
  612. // linux_.snd_nxt  this variable is directly controlled by ack_processing() and send_much()
  613. // linux_.snd_una  this variable is directly controlled by ack_processing()
  614. // linux_.srtt     this variable is directly controlled by rtt_update()
  615. //      snd_cwnd_stamp  this variable is directly controlled by touch_cwnd()
  616. // linux_.rx_opt.rcv_tsecr is directly controled in ack_processing()
  617. // linux_.rx_opt.saw_tstamp is directly controled in ack_processing()
  618. // snd_cwnd_stamp this variable is directly controled by touch_cwnd()
  619. //remark:
  620. //snd_una == (highest_ack+1)*mss_cache
  621. //snd_nxt == (t_seqno)*mss_cache
  622. };
  623. void LinuxTcpAgent::save_from_linux()
  624. {
  625. //TODO
  626. if (next_pkts_in_flight_ > (int)linux_.snd_cwnd) 
  627. cwnd_ = next_pkts_in_flight_; 
  628. else
  629. cwnd_ = linux_.snd_cwnd;
  630. // + min(((double)linux_.snd_cwnd_cnt/(double)linux_.snd_cwnd),1);
  631. ssthresh_ = linux_.snd_ssthresh;
  632. // for legacy variables:
  633. last_ack_ = highest_ack_;
  634. };
  635. void LinuxTcpAgent::load_to_linux_once() {
  636. linux_.snd_cwnd_clamp = (long unsigned) round(wnd_);
  637. linux_.snd_ssthresh = linux_.snd_cwnd_clamp;
  638. linux_.mss_cache = size_;
  639. }
  640. char LinuxTcpAgent::install_congestion_control(const char* name)
  641. {
  642. struct tcp_congestion_ops* newops = cong_ops_manager.get_ops(name);
  643. if (newops) {
  644. if (linux_.icsk_ca_ops!=newops) {
  645. //release any existing congestion control algorithm before install
  646.                  if (linux_.icsk_ca_ops !=NULL ) {
  647. if (linux_.icsk_ca_ops->release) 
  648. linux_.icsk_ca_ops->release(&linux_);
  649. save_from_linux();
  650. } else {
  651. load_to_linux_once();
  652. load_to_linux(); //it was controlled by NS2, load to Linux
  653. tcp_tick_ = 1.0/(double)JIFFY_RATIO;
  654. }
  655. linux_.icsk_ca_ops = newops;
  656. if ((initialized_) && (newops->init)) {
  657. //if the algorithm is changed in the middle, we need to intialize the module
  658. newops->init(&linux_);
  659. }
  660. if ((linux_.icsk_ca_ops->flags & TCP_CONG_RTT_STAMP)  || (linux_.icsk_ca_ops->rtt_sample)) {
  661. bugfix_ts_=1;
  662. // if rtt_sample exists, we must turn on the sender-side timestamp record to provide accurate rtt in microsecond.
  663. }
  664. save_from_linux();
  665. }
  666. return TRUE;
  667. } else {
  668. return FALSE;
  669. }
  670. };
  671. void LinuxTcpAgent::remove_congestion_control()
  672. {
  673. if (linux_.icsk_ca_ops != NULL) {
  674. if (linux_.icsk_ca_ops->release)
  675. linux_.icsk_ca_ops->release(&linux_);
  676. save_from_linux();
  677. linux_.icsk_ca_ops = NULL;
  678. }
  679. };
  680. int LinuxTcpAgent::command(int argc, const char*const* argv) 
  681. {
  682. if ((argc>=3) && (strcmp(argv[1], "select_ca")==0)) {
  683. printf("%s %s %sn", argv[0], argv[1], argv[2]);
  684. if (install_congestion_control(argv[2])==FALSE) {
  685. printf("Error: do not find %s as a congestion control algorithmn", argv[2]);
  686. cong_ops_manager.dump();
  687. }
  688. return (TCL_OK);
  689. };
  690. if ((argc>=5) && (strcmp(argv[1], "set_ca_param")==0)) {
  691. printf("%s %s %s %s %sn", argv[0], argv[1], argv[2], argv[3], argv[4]);
  692. if (!paramManager.set_param(argv[2], argv[3], atoi(argv[4]))) {
  693. printf("Error: do not find %s as a parameter for congestion control algorithm %sn", argv[3], argv[2]);
  694. };
  695. return (TCL_OK);
  696. };
  697. if ((argc>=4) && (strcmp(argv[1], "get_ca_param")==0)) {
  698. printf("%s %s %s %sn", argv[0], argv[1], argv[2], argv[3]);
  699. int res;
  700. if (!paramManager.get_param(argv[2], argv[3], &res)) {
  701. printf("Error: do not find %s as a parameter for congestion control algorithm %sn", argv[3], argv[2]);
  702. } else {
  703. printf("tcp_%s.%s = %dn", argv[2], argv[3], res);
  704. };
  705. return (TCL_OK);
  706. };
  707. if ((argc>=5) && (strcmp(argv[1], "set_ca_default_param")==0)) {
  708. printf("%s %s %s %s %sn", argv[0], argv[1], argv[2], argv[3], argv[4]);
  709. if (!paramManager.set_default_param(argv[2], argv[3], atoi(argv[4]))) {
  710. printf("Error: do not find %s as a parameter for congestion control algorithm %sn", argv[3], argv[2]);
  711. };
  712. return (TCL_OK);
  713. };
  714. if ((argc>=4) && (strcmp(argv[1], "get_ca_default_param")==0)) {
  715. printf("%s %s %s %sn", argv[0], argv[1], argv[2], argv[3]);
  716. int res;
  717. if (!paramManager.get_default_param(argv[2], argv[3], &res)) {
  718. printf("Error: do not find %s as a parameter for congestion control algorithm %sn", argv[3], argv[2]);
  719. } else {
  720. printf("tcp_%s.%s = %dn", argv[2], argv[3], res);
  721. };
  722. return (TCL_OK);
  723. };
  724. if ((argc==3) && (strcmp(argv[1], "get_ca_param")==0)) {
  725. printf("%s %s %sn", argv[0], argv[1], argv[2]);
  726. if (!paramManager.query_param(argv[2])) {
  727. printf("Error: %s is not a congestion control algorithm or has no parametern", argv[2]);
  728. };
  729. return (TCL_OK);
  730. };
  731. return (TcpAgent::command(argc, argv));
  732. }
  733. void LinuxTcpAgent::plot()
  734. {
  735. #ifdef notyet
  736. double t = Scheduler::instance().clock();
  737. sprintf(trace_->buffer(), "t %g %d rtt %gn", 
  738. t, class_, t_rtt_ * tcp_tick_);
  739. trace_->dump();
  740. sprintf(trace_->buffer(), "t %g %d dev %gn", 
  741. t, class_, t_rttvar_ * tcp_tick_);
  742. trace_->dump();
  743. sprintf(trace_->buffer(), "t %g %d win %fn", t, class_, cwnd_);
  744. trace_->dump();
  745. sprintf(trace_->buffer(), "t %g %d bck %dn", t, class_, t_backoff_);
  746. trace_->dump();
  747. #endif
  748. }
  749. /* Implementation of LinuxParamManager */
  750. struct cc_list* LinuxParamManager::find_cc_by_proto(const char* proto) {
  751. struct cc_list* p = cc_list_head;
  752. char proto_name[100];
  753. snprintf(proto_name, 100, "tcp_%s.c", proto);
  754. while (p!=NULL && (strcmp(p->proto, proto_name)!=0)) p=p->next;
  755. return p;
  756. };
  757. struct cc_param_list* LinuxParamManager::find_param_by_proto_name(const char* proto, const char* name) {
  758. struct cc_list* p = find_cc_by_proto(proto);
  759. if (!p) return NULL;
  760. struct cc_param_list* q = p->param_head;
  761. while (q!=NULL && ((strcmp(q->name, name)!=0)||(strcmp(q->type, "int")!=0))) q=q->next;
  762. return q;
  763. };
  764. bool LinuxParamManager::set_default_param(const char* proto, const char* param, const int value) {
  765. struct cc_param_list* p = find_param_by_proto_name(proto, param);
  766. if (!p) return false;
  767. (*(int*)p->ptr) = value;
  768. return true;
  769. };
  770. bool LinuxParamManager::set_param(const char* proto, const char* param, const int value) {
  771. struct cc_param_list* p = find_param_by_proto_name(proto, param);
  772. if (!p) return false;
  773. localValues.set_param((int*)p->ptr, value);
  774. return true;
  775. };
  776. bool LinuxParamManager::get_default_param(const char* proto, const char* param, int* valuep) {
  777. struct cc_param_list* p = find_param_by_proto_name(proto, param);
  778. if (!p) return false;
  779. *valuep = *((int*)(p->ptr));
  780. return true;
  781. };
  782. bool LinuxParamManager::get_param(const char* proto, const char* param, int* valuep) {
  783. struct cc_param_list* p = find_param_by_proto_name(proto, param);
  784. if (!p) return false;
  785. if (localValues.get_param((int*)p->ptr, valuep)) return true;
  786. *valuep = *((int*)(p->ptr));
  787. return true;
  788. };
  789. bool LinuxParamManager::query_param(const char* proto) {
  790. struct cc_list* p = find_cc_by_proto(proto);
  791. if (!p) {
  792. printf("%s has no parameter registeredn", proto);
  793. return false;
  794. };
  795. printf("Parameter list for %s:n", proto);
  796. struct cc_param_list* q = p->param_head;
  797. while (q != NULL) {
  798. printf(" %s = %d (%s)n", q->name, *((int*)q->ptr), q->description);
  799. q = q->next;
  800. }; 
  801. return true;
  802. };
  803. /** Get a local value for a TCP */
  804. bool ParamList::get_param(int* address, int* valuep) {
  805. struct paramNode *p = head;
  806. while (p && (p->addr != address)) p = p->next;
  807. if (p) {
  808. *valuep = p->value;
  809. return true;
  810. };
  811. return false;
  812. };
  813. /** Set a local value for a TCP */
  814. void ParamList::set_param(int* address, int value) {
  815. struct paramNode *p = head;
  816. while ((p) && (p->addr != address)) {
  817. p = p->next;
  818. };
  819. if (p) {
  820. //we find one.
  821. p->value = value;
  822. return;
  823. };
  824. //Cannot find any
  825. //Create a new entry
  826. p = new struct paramNode;
  827. p->addr = address; 
  828. p->value = value;
  829. p->default_value = *address;
  830. p->next = head;
  831. head = p;
  832. };
  833. /** Refresh all the values in the list */
  834. void ParamList::refresh_default() {
  835. struct paramNode *p = head;
  836. while (p) {
  837. p->default_value = *(p->addr);
  838. p = p->next;
  839. };
  840. };
  841. void ParamList::restore_default() {
  842. struct paramNode *p = head;
  843. while (p) {
  844. p->value = *(p->addr);
  845. *(p->addr) = p->default_value;
  846. p = p->next;
  847. };
  848. };
  849. void ParamList::load_local() {
  850. struct paramNode *p = head;
  851. while (p) {
  852. p->default_value = *(p->addr);
  853. *(p->addr) = p->value;
  854. p = p->next;
  855. };
  856. };
  857. ParamList::~ParamList() {
  858. while (head) {
  859. struct paramNode *p = head;
  860. head = head->next;
  861. delete p;
  862. };
  863. };