home *** CD-ROM | disk | FTP | other *** search
/ Handbook of Infosec Terms 2.0 / Handbook_of_Infosec_Terms_Version_2.0_ISSO.iso / text / rfcs / rfc0817.txt < prev    next >
Text File  |  1996-05-07  |  48KB  |  1,287 lines

  1.  RFC:  817 
  2.  
  3.  
  4.  
  5.           MODULARITY AND EFFICIENCY IN PROTOCOL IMPLEMENTATION 
  6.  
  7.                              David D. Clark                   MIT Laboratory for Computer Science                Computer Systems and Communications Group                                July, 1982 
  8.  
  9.       1.  Introduction 
  10.  
  11.       Many  protocol implementers have made the unpleasant discovery that 
  12.  
  13. their packages do not run quite as fast as they had hoped.    The  blame 
  14.  
  15. for  this  widely  observed  problem has been attributed to a variety of 
  16.  
  17. causes, ranging from details in  the  design  of  the  protocol  to  the 
  18.  
  19. underlying  structure  of  the  host  operating  system.   This RFC will 
  20.  
  21. discuss  some  of  the  commonly  encountered   reasons   why   protocol 
  22.  
  23. implementations seem to run slowly. 
  24.  
  25.       Experience  suggests  that  one  of  the  most important factors in 
  26.  
  27. determining the performance of an implementation is the manner in  which 
  28.  
  29. that   implementation  is  modularized  and  integrated  into  the  host 
  30.  
  31. operating system.  For this reason, it is useful to discuss the question 
  32.  
  33. of how an implementation is structured at the same time that we consider 
  34.  
  35. how it will perform.  In fact, this RFC will argue  that  modularity  is 
  36.  
  37. one  of  the chief villains in attempting to obtain good performance, so 
  38.  
  39. that the designer is faced  with  a  delicate  and  inevitable  tradeoff 
  40.  
  41. between good structure and good performance.  Further, the single factor 
  42.  
  43. which most strongly determines how well this conflict can be resolved is 
  44.  
  45. not the protocol but the operating system. 
  46.                                     2 
  47.  
  48.       2.  Efficiency Considerations 
  49.  
  50.       There  are  many aspects to efficiency.  One aspect is sending data 
  51.  
  52. at minimum transmission cost, which  is  a  critical  aspect  of  common 
  53.  
  54. carrier  communications,  if  not  in local area network communications. 
  55.  
  56. Another aspect is sending data at a high rate, which may not be possible 
  57.  
  58. at all if the net is very slow, but which may be the one central  design 
  59.  
  60. constraint when taking advantage of a local net with high raw bandwidth. 
  61.  
  62. The  final  consideration is doing the above with minimum expenditure of 
  63.  
  64. computer resources.  This last may be necessary to achieve  high  speed, 
  65.  
  66. but  in  the  case  of  the  slow  net may be important only in that the 
  67.  
  68. resources used up, for example  cpu  cycles,  are  costly  or  otherwise 
  69.  
  70. needed.    It  is  worth  pointing  out that these different goals often 
  71.  
  72. conflict; for example it is often possible to trade off efficient use of 
  73.  
  74. the computer against efficient use of the network.  Thus, there  may  be 
  75.  
  76. no such thing as a successful general purpose protocol implementation. 
  77.  
  78.       The simplest measure of performance is throughput, measured in bits 
  79.  
  80. per second.  It is worth doing a few simple computations in order to get 
  81.  
  82. a  feeling for the magnitude of the problems involved.  Assume that data 
  83.  
  84. is being sent from one machine to another in packets of 576  bytes,  the 
  85.  
  86. maximum  generally acceptable internet packet size.  Allowing for header 
  87.  
  88. overhead, this packet size permits 4288 bits  in  each  packet.    If  a 
  89.  
  90. useful  throughput  of  10,000  bits  per second is desired, then a data 
  91.  
  92. bearing packet must leave the sending host about every 430 milliseconds, 
  93.  
  94. a little over two per second.  This is clearly not difficult to achieve. 
  95.  
  96. However, if one wishes to achieve 100 kilobits  per  second  throughput, 
  97.                                     3 
  98.  
  99.  the packet must leave the host every 43 milliseconds, and to achieve one 
  100.  
  101. megabit  per  second,  which  is not at all unreasonable on a high-speed 
  102.  
  103. local net, the packets must be spaced no more than 4.3 milliseconds. 
  104.  
  105.       These latter numbers are a slightly more alarming goal for which to 
  106.  
  107. set one's sights.  Many operating systems take a substantial fraction of 
  108.  
  109. a millisecond just to service an interrupt.  If the  protocol  has  been 
  110.  
  111. structured  as  a  process,  it  is  necessary  to  go through a process 
  112.  
  113. scheduling before the protocol code can even begin to run.  If any piece 
  114.  
  115. of a protocol package or its data must be fetched from disk,  real  time 
  116.  
  117. delays  of  between  30  to  100  milliseconds  can be expected.  If the 
  118.  
  119. protocol must compete for cpu resources  with  other  processes  of  the 
  120.  
  121. system,  it  may  be  necessary  to wait a scheduling quantum before the 
  122.  
  123. protocol can run.   Many  systems  have  a  scheduling  quantum  of  100 
  124.  
  125. milliseconds  or  more.   Considering these sorts of numbers, it becomes 
  126.  
  127. immediately clear that the protocol must be fitted  into  the  operating 
  128.  
  129. system  in  a  thorough  and  effective  manner  if  any like reasonable 
  130.  
  131. throughput is to be achieved. 
  132.  
  133.       There is one obvious conclusion immediately suggested by even  this 
  134.  
  135. simple  analysis.    Except  in  very  special  circumstances, when many 
  136.  
  137. packets are being processed at once, the cost of processing a packet  is 
  138.  
  139. dominated  by  factors, such as cpu scheduling, which are independent of 
  140.  
  141. the  packet  size.    This  suggests  two  general   rules   which   any 
  142.  
  143. implementation  ought  to  obey.    First,  send  data in large packets. 
  144.  
  145. Obviously, if processing time per packet is a constant, then  throughput 
  146.  
  147. will be directly proportional to the packet size.  Second, never send an 
  148.                                     4 
  149.  
  150.  unneeded  packet.    Unneeded packets use up just as many resources as a 
  151.  
  152. packet full of data, but perform no useful function.  RFC  813,  "Window 
  153.  
  154. and  Acknowledgement  Strategy in TCP", discusses one aspect of reducing 
  155.  
  156. the number of packets sent per useful data byte.    This  document  will 
  157.  
  158. mention other attacks on the same problem. 
  159.  
  160.       The  above  analysis  suggests that there are two main parts to the 
  161.  
  162. problem of achieving good protocol performance.  The  first  has  to  do 
  163.  
  164. with  how  the  protocol  implementation  is  integrated  into  the host 
  165.  
  166. operating system.  The second has to do with how  the  protocol  package 
  167.  
  168. itself  is  organized  internally.   This document will consider each of 
  169.  
  170. these topics in turn. 
  171.  
  172.       3.  The Protocol vs. the Operating System 
  173.  
  174.       There are normally three reasonable ways in which to add a protocol 
  175.  
  176. to an operating system.  The protocol  can  be  in  a  process  that  is 
  177.  
  178. provided by the operating system, or it can be part of the kernel of the 
  179.  
  180. operating  system  itself, or it can be put in a separate communications 
  181.  
  182. processor or front end machine.  This decision is strongly influenced by 
  183.  
  184. details of hardware architecture and operating system  design;  each  of 
  185.  
  186. these three approaches has its own advantages and disadvantages. 
  187.  
  188.       The  "process"  is the abstraction which most operating systems use 
  189.  
  190. to provide the execution environment for user programs.  A  very  simple 
  191.  
  192. path  for  implementing  a  protocol  is  to  obtain  a process from the 
  193.  
  194. operating  system  and  implement   the   protocol   to   run   in   it. 
  195.  
  196. Superficially,  this  approach  has  a  number  of  advantages.    Since 
  197.                                     5 
  198.  
  199.  modifications  to  the  kernel  are not required, the job can be done by 
  200.  
  201. someone who is not an expert in the kernel structure.  Since it is often 
  202.  
  203. impossible to find somebody who is experienced both in the structure  of 
  204.  
  205. the  operating system and the structure of the protocol, this path, from 
  206.  
  207. a management point of view, is often extremely appealing. Unfortunately, 
  208.  
  209. putting a protocol in a process has a number of  disadvantages,  related 
  210.  
  211. to  both  structure  and  performance.    First, as was discussed above, 
  212.  
  213. process scheduling can be  a  significant  source  of  real-time  delay. 
  214.  
  215. There  is  not  only the actual cost of going through the scheduler, but 
  216.  
  217. the problem that the operating system may not have  the  right  sort  of 
  218.  
  219. priority  tools  to  bring  the  process into execution quickly whenever 
  220.  
  221. there is work to be done. 
  222.  
  223.       Structurally, the difficulty with putting a protocol in  a  process 
  224.  
  225. is  that  the protocol may be providing services, for example support of 
  226.  
  227. data streams, which are normally obtained by  going  to  special  kernel 
  228.  
  229. entry  points.   Depending on the generality of the operating system, it 
  230.  
  231. may be impossible to take a  program  which  is  accustomed  to  reading 
  232.  
  233. through  a kernel entry point, and redirect it so it is reading the data 
  234.  
  235. from a process.  The most extreme example of this  problem  occurs  when 
  236.  
  237. implementing  server  telnet.  In almost all systems, the device handler  for the locally attached teletypes is located  inside  the  kernel,  and 
  238.  
  239. programs  read and write from their teletype by making kernel calls.  If 
  240.  
  241. server telnet is implemented in a process, it is then necessary to  take 
  242.  
  243. the  data  streams  provided  by server telnet and somehow get them back 
  244.  
  245. down inside the kernel so that they  mimic  the  interface  provided  by 
  246.  
  247. local   teletypes.     It  is  usually  the  case  that  special  kernel 
  248.                                     6 
  249.  
  250.  modification  is  necessary  to  achieve  this structure, which somewhat 
  251.  
  252. defeats the benefit of having removed the protocol from  the  kernel  in 
  253.  
  254. the first place. 
  255.  
  256.       Clearly, then, there are advantages to putting the protocol package 
  257.  
  258. in  the kernel.  Structurally, it is reasonable to view the network as a 
  259.  
  260. device, and device drivers are traditionally contained  in  the  kernel. 
  261.  
  262. Presumably,  the  problems  associated  with  process  scheduling can be 
  263.  
  264. sidesteped, at least to a certain extent, by placing the code inside the 
  265.  
  266. kernel.  And it is obviously easier to make the server  telnet  channels 
  267.  
  268. mimic  the local teletype channels if they are both realized in the same 
  269.  
  270. level in the kernel. 
  271.  
  272.       However, implementation of protocols in the kernel has its own  set 
  273.  
  274. of  pitfalls.    First, network protocols have a characteristic which is 
  275.  
  276. shared by almost no other device:  they require rather  complex  actions 
  277.  
  278. to  be  performed  as  a  result  of  a  timeout.  The problem with this 
  279.  
  280. requirement is that the kernel often has no facility by which a  program 
  281.  
  282. can  be  brought into execution as a result of the timer event.  What is 
  283.  
  284. really needed, of course, is  a  special  sort  of  process  inside  the 
  285.  
  286. kernel.    Most  systems  lack  this  mechanism.  Failing that, the only 
  287.  
  288. execution mechanism available is to run at interrupt time. 
  289.  
  290.       There are substantial drawbacks to implementing a protocol  to  run 
  291.  
  292. at interrupt time.  First, the actions performed may be somewhat complex 
  293.  
  294. and  time  consuming,  compared  to  the maximum amount of time that the 
  295.  
  296. operating system is prepared to spend servicing an interrupt.   Problems 
  297.  
  298. can  arise  if interrupts are masked for too long.  This is particularly 
  299.                                     7 
  300.  
  301.  bad  when running as a result of a clock interrupt, which can imply that 
  302.  
  303. the clock interrupt is masked.  Second, the environment provided  by  an 
  304.  
  305. interrupt  handler  is  usually  extremely  primitive  compared  to  the 
  306.  
  307. environment of a process.    There  are  usually  a  variety  of  system 
  308.  
  309. facilities  which are unavailable while running in an interrupt handler. 
  310.  
  311. The most important of these is the ability to suspend execution  pending 
  312.  
  313. the  arrival  of some event or message.  It is a cardinal rule of almost 
  314.  
  315. every known operating system that one  must  not  invoke  the  scheduler 
  316.  
  317. while  running  in  an  interrupt  handler.  Thus, the programmer who is 
  318.  
  319. forced to implement all or part of his protocol package as an  interrupt 
  320.  
  321. handler  must  be  the  best  sort  of  expert  in  the operating system 
  322.  
  323. involved, and must be prepared  for  development  sessions  filled  with 
  324.  
  325. obscure  bugs  which  crash not just the protocol package but the entire 
  326.  
  327. operating system. 
  328.  
  329.       A final problem with processing  at  interrupt  time  is  that  the 
  330.  
  331. system  scheduler has no control over the percentage of system time used 
  332.  
  333. by the protocol handler.  If a large number of packets  arrive,  from  a 
  334.  
  335. foreign  host that is either malfunctioning or fast, all of the time may 
  336.  
  337. be spent in the interrupt handler, effectively killing the system. 
  338.  
  339.       There are other problems associated with putting protocols into  an 
  340.  
  341. operating system kernel.  The simplest problem often encountered is that 
  342.  
  343. the  kernel  address space is simply too small to hold the piece of code 
  344.  
  345. in question.  This is a rather artificial sort of problem, but it  is  a 
  346.  
  347. severe  problem  none  the  less in many machines.  It is an appallingly 
  348.  
  349. unpleasant experience to do an implementation with  the  knowledge  that 
  350.                                     8 
  351.  
  352.  for  every  byte  of new feature put in one must find some other byte of 
  353.  
  354. old feature to throw out.  It is hopeless to  expect  an  effective  and 
  355.  
  356. general  implementation  under this kind of constraint.  Another problem 
  357.  
  358. is that the protocol package, once it  is  thoroughly  entwined  in  the 
  359.  
  360. operating  system, may need to be redone every time the operating system 
  361.  
  362. changes.  If the protocol and the operating system are not maintained by 
  363.  
  364. the same group,  this  makes  maintenance  of  the  protocol  package  a 
  365.  
  366. perpetual headache. 
  367.  
  368.       The  third  option  for  protocol  implementation  is  to  take the 
  369.  
  370. protocol package and move it outside  the  machine  entirely,  on  to  a 
  371.  
  372. separate  processor  dedicated  to this kind of task.  Such a machine is 
  373.  
  374. often described as a communications processor or a front-end  processor. 
  375.  
  376. There  are  several  advantages  to this approach.  First, the operating 
  377.  
  378. system on the communications processor can  be  tailored  for  precisely 
  379.  
  380. this  kind  of  task.  This makes the job of implementation much easier. 
  381.  
  382. Second, one does not need to redo the task for every  machine  to  which 
  383.  
  384. the  protocol  is  to  be  added.   It may be possible to reuse the same 
  385.  
  386. front-end machine on different host computers.  Since the task need  not 
  387.  
  388. be  done as many times, one might hope that more attention could be paid 
  389.  
  390. to doing it right.  Given a careful  implementation  in  an  environment 
  391.  
  392. which  is  optimized for this kind of task, the resulting package should 
  393.  
  394. turn out to be very efficient.  Unfortunately, there are  also  problems 
  395.  
  396. with this approach.  There is, of course, a financial problem associated 
  397.  
  398. with  buying  an  additional  computer.    In  many cases, this is not a 
  399.  
  400. problem at all since  the  cost  is  negligible  compared  to  what  the 
  401.  
  402. programmer  would  cost  to  do  the  job in the mainframe itself.  More 
  403.                                     9 
  404.  
  405.  fundamentally, the communications processor approach does not completely 
  406.  
  407. sidestep  any  of  the  problems  raised  above.  The reason is that the 
  408.  
  409. communications processor, since  it  is  a  separate  machine,  must  be 
  410.  
  411. attached  to  the mainframe by some mechanism.  Whatever that mechanism, 
  412.  
  413. code is required in the mainframe to deal with it.   It  can  be  argued 
  414.  
  415. that  the  program  to deal with the communications processor is simpler 
  416.  
  417. than the program to implement the entire protocol package.  Even if that 
  418.  
  419. is so,  the  communications  processor  interface  package  is  still  a 
  420.  
  421. protocol in nature, with all of the same structural problems.  Thus, all 
  422.  
  423. of  the  issues  raised above must still be faced.  In addition to those 
  424.  
  425. problems, there are some other, more subtle problems associated with  an 
  426.  
  427. outboard implementation of a protocol.  We will return to these problems 
  428.  
  429. later. 
  430.  
  431.       There  is  a  way  of  attaching  a  communications  processor to a 
  432.  
  433. mainframe host which  sidesteps  all  of  the  mainframe  implementation 
  434.  
  435. problems, which is to use some preexisting interface on the host machine 
  436.  
  437. as  the  port  by  which  a  communications processor is attached.  This 
  438.  
  439. strategy is often used as a last stage of desperation when the  software 
  440.  
  441. on  the host computer is so intractable that it cannot be changed in any 
  442.  
  443. way.  Unfortunately, it is almost inevitably the case that  all  of  the 
  444.  
  445. available  interfaces  are  totally  unsuitable for this purpose, so the 
  446.  
  447. result is unsatisfactory at best.  The most common  way  in  which  this 
  448.  
  449. form  of attachment occurs is when a network connection is being used to 
  450.  
  451. mimic local teletypes.  In this case, the  front-end  processor  can  be 
  452.  
  453. attached  to  the mainframe by simply providing a number of wires out of 
  454.  
  455. the front-end processor, each corresponding to a connection,  which  are 
  456.                                     10 
  457.  
  458.  plugged  into teletype ports on the mainframe computer.  (Because of the 
  459.  
  460. appearance  of  the  physical  configuration  which  results  from  this 
  461.  
  462. arrangement,  Michael  Padlipsky  has  described  this  as  the "milking 
  463.  
  464. machine" approach to computer networking.)   This  strategy  solves  the 
  465.  
  466. immediate  problem  of  providing  remote  access  to  a host, but it is 
  467.  
  468. extremely inflexible.  The channels  being  provided  to  the  host  are 
  469.  
  470. restricted  by  the host software to one purpose only, remote login.  It 
  471.  
  472. is impossible to use them for any other purpose, such as  file  transfer 
  473.  
  474. or  sending mail, so the host is integrated into the network environment 
  475.  
  476. in an extremely limited and inflexible manner.  If this is the best that 
  477.  
  478. can be done, then it  should  be  tolerated.    Otherwise,  implementors 
  479.  
  480. should be strongly encouraged to take a more flexible approach. 
  481.  
  482.       4.  Protocol Layering 
  483.  
  484.       The  previous  discussion suggested that there was a decision to be 
  485.  
  486. made as to where a protocol ought to  be  implemented.    In  fact,  the 
  487.  
  488. decision  is  much  more  complicated  than that, for the goal is not to 
  489.  
  490. implement a single protocol, but to implement a whole family of protocol 
  491.  
  492. layers, starting with a device driver or local  network  driver  at  the 
  493.  
  494. bottom,  then  IP  and  TCP,  and  eventually  reaching  the application 
  495.  
  496. specific protocol, such as Telnet, FTP and SMTP on the  top.    Clearly, 
  497.  
  498. the bottommost of these layers is somewhere within the kernel, since the 
  499.  
  500. physical  device  driver for the net is almost inevitably located there. 
  501.  
  502. Equally clearly, the top layers of this package, which provide the  user 
  503.  
  504. his  ability  to  perform the remote login function or to send mail, are 
  505.  
  506. not entirely contained within the kernel.  Thus,  the  question  is  not 
  507.                                     11 
  508.  
  509.  whether  the  protocol family shall be inside or outside the kernel, but 
  510.  
  511. how it shall be sliced in two between that part  inside  and  that  part 
  512.  
  513. outside. 
  514.  
  515.       Since  protocols  come  nicely layered, an obvious proposal is that 
  516.  
  517. one of the layer interfaces should be the point at which the inside  and 
  518.  
  519. outside components are sliced apart.  Most systems have been implemented 
  520.  
  521. in  this  way,  and  many have been made to work quite effectively.  One 
  522.  
  523. obvious place to slice is at the upper interface  of  TCP.    Since  TCP 
  524.  
  525. provides  a  bidirectional byte stream, which is somewhat similar to the 
  526.  
  527. I/O facility provided by most operating systems, it is possible to  make 
  528.  
  529. the  interface  to  TCP  almost  mimic  the  interface to other existing 
  530.  
  531. devices.  Except in the matter of opening a connection, and dealing with 
  532.  
  533. peculiar failures, the software using TCP need not know  that  it  is  a 
  534.  
  535. network connection, rather than a local I/O stream that is providing the 
  536.  
  537. communications  function.  This approach does put TCP inside the kernel, 
  538.  
  539. which raises all the problems addressed  above.    It  also  raises  the 
  540.  
  541. problem that the interface to the IP layer can, if the programmer is not 
  542.  
  543. careful,  become  excessively  buried  inside  the  kernel.   It must be 
  544.  
  545. remembered that things other than TCP are expected to run on top of  IP. 
  546.  
  547. The  IP interface must be made accessible, even if TCP sits on top of it 
  548.  
  549. inside the kernel. 
  550.  
  551.       Another obvious place to slice is above Telnet.  The  advantage  of 
  552.  
  553. slicing  above  Telnet  is  that  it solves the problem of having remote 
  554.  
  555. login channels emulate local teletype channels.    The  disadvantage  of 
  556.  
  557. putting  Telnet into the kernel is that the amount of code which has now 
  558.                                     12 
  559.  
  560.  been  included  there  is  getting  remarkably  large.    In  some early 
  561.  
  562. implementations, the size of the  network  package,  when  one  includes 
  563.  
  564. protocols  at  the  level  of Telnet, rivals the size of the rest of the 
  565.  
  566. supervisor.  This leads to vague feelings that all is not right. 
  567.  
  568.       Any attempt to slice through a lower layer  boundary,  for  example 
  569.  
  570. between  internet  and  TCP,  reveals  one fundamental problem.  The TCP 
  571.  
  572. layer, as well as the IP layer, performs a  demultiplexing  function  on 
  573.  
  574. incoming  datagrams.   Until the TCP header has been examined, it is not 
  575.  
  576. possible to know for which  user  the  packet  is  ultimately  destined. 
  577.  
  578. Therefore,  if  TCP,  as  a  whole,  is  moved outside the kernel, it is 
  579.  
  580. necessary to create one separate process called the TCP  process,  which 
  581.  
  582. performs  the TCP multiplexing function, and probably all of the rest of 
  583.  
  584. TCP processing as well.  This means that incoming data  destined  for  a 
  585.  
  586. user  process  involves  not  just a scheduling of the user process, but 
  587.  
  588. scheduling the TCP process first. 
  589.  
  590.       This suggests an  alternative  structuring  strategy  which  slices 
  591.  
  592. through  the  protocols,  not  along  an established layer boundary, but 
  593.  
  594. along a functional boundary having to do with demultiplexing.   In  this 
  595.  
  596. approach, certain parts of IP and certain parts of TCP are placed in the 
  597.  
  598. kernel.    The amount of code placed there is sufficient so that when an 
  599.  
  600. incoming datagram arrives, it is possible to know for which process that 
  601.  
  602. datagram is ultimately destined.  The datagram is then  routed  directly 
  603.  
  604. to  the  final  process,  where  additional  IP  and  TCP  processing is 
  605.  
  606. performed on it.  This removes from the kernel any requirement for timer 
  607.  
  608. based actions, since they can be done by the  process  provided  by  the 
  609.                                     13 
  610.  
  611.  user.    This  structure  has  the  additional advantage of reducing the 
  612.  
  613. amount of code required in the  kernel,  so  that  it  is  suitable  for 
  614.  
  615. systems where kernel space is at a premium.  The RFC 814, titled "Names, 
  616.  
  617. Addresses,  Ports, and Routes," discusses this rather orthogonal slicing 
  618.  
  619. strategy in more detail. 
  620.  
  621.       A related discussion of protocol layering and multiplexing  can  be 
  622.  
  623. found in Cohen and Postel [1]. 
  624.  
  625.       5.  Breaking Down the Barriers 
  626.  
  627.       In  fact, the implementor should be sensitive to the possibility of 
  628.  
  629. even more  peculiar  slicing  strategies  in  dividing  up  the  various 
  630.  
  631. protocol  layers  between the kernel and the one or more user processes. 
  632.  
  633. The result of the strategy proposed above was that part  of  TCP  should 
  634.  
  635. execute  in  the process of the user.  In other words, instead of having 
  636.  
  637. one TCP process for the system, there is one TCP process per connection. 
  638.  
  639. Given this architecture, it is not longer necessary to imagine that  all 
  640.  
  641. of  the  TCPs  are  identical.    One  TCP  could  be optimized for high 
  642.  
  643. throughput applications, such as file transfer.  Another  TCP  could  be 
  644.  
  645. optimized  for small low delay applications such as Telnet.  In fact, it 
  646.  
  647. would be possible to produce a TCP which was  somewhat  integrated  with 
  648.  
  649. the  Telnet  or  FTP  on  top  of  it.  Such an integration is extremely 
  650.  
  651. important,  for  it  can  lead  to  a  kind  of  efficiency  which  more 
  652.  
  653. traditional  structures are incapable of producing.  Earlier, this paper 
  654.  
  655. pointed out that one of the important rules to achieving efficiency  was 
  656.  
  657. to  send  the minimum number of packets for a given amount of data.  The 
  658.  
  659. idea of protocol layering interacts very strongly (and poorly) with this 
  660.                                     14 
  661.  
  662.  goal,  because  independent  layers  have  independent  ideas about when 
  663.  
  664. packets should be sent, and unless these layers can somehow  be  brought 
  665.  
  666. into  cooperation,  additional  packets  will flow.  The best example of 
  667.  
  668. this is the operation of server telnet in a character at a  time  remote 
  669.  
  670. echo  mode  on top of TCP.  When a packet containing a character arrives 
  671.  
  672. at a server host, each layer has a different response  to  that  packet. 
  673.  
  674. TCP  has  an obligation to acknowledge the packet.  Either server telnet 
  675.  
  676. or the application layer above has an obligation to echo  the  character 
  677.  
  678. received  in the packet.  If the character is a Telnet control sequence, 
  679.  
  680. then Telnet has additional actions which it must perform in response  to 
  681.  
  682. the  packet.    The  result  of  this,  in most implementations, is that 
  683.  
  684. several packets are sent back in response to the  one  arriving  packet. 
  685.  
  686. Combining  all of these return messages into one packet is important for 
  687.  
  688. several reasons.  First, of course, it reduces  the  number  of  packets 
  689.  
  690. being sent over the net, which directly reduces the charges incurred for 
  691.  
  692. many common carrier tariff structures.  Second, it reduces the number of 
  693.  
  694. scheduling  actions  which  will  occur inside both hosts, which, as was 
  695.  
  696. discussed above, is extremely important in improving throughput. 
  697.  
  698.       The way to achieve this goal of packet sharing is to break down the 
  699.  
  700. barrier between the layers of the protocols, in a  very  restrained  and 
  701.  
  702. careful  manner, so that a limited amount of information can leak across 
  703.  
  704. the barrier to enable one layer to optimize its behavior with respect to 
  705.  
  706. the desires of the layers above and below it.   For  example,  it  would 
  707.  
  708. represent  an  improvement  if TCP, when it received a packet, could ask 
  709.  
  710. the layer above whether or not it would  be  worth  pausing  for  a  few 
  711.  
  712. milliseconds  before  sending  an acknowledgement in order to see if the 
  713.                                     15 
  714.  
  715.  upper  layer  would  have  any  outgoing  data to send.  Dallying before 
  716.  
  717. sending  the  acknowledgement  produces  precisely  the  right  sort  of 
  718.  
  719. optimization  if  the client of TCP is server Telnet.  However, dallying 
  720.  
  721. before sending an acknowledgement is absolutely unacceptable if  TCP  is 
  722.  
  723. being used for file transfer, for in file transfer there is almost never 
  724.  
  725. data  flowing  in  the  reverse  direction, and the delay in sending the 
  726.  
  727. acknowledgement probably translates directly into a delay  in  obtaining 
  728.  
  729. the  next  packets.  Thus, TCP must know a little about the layers above 
  730.  
  731. it to adjust its performance as needed. 
  732.  
  733.       It would be possible to imagine a general  purpose  TCP  which  was 
  734.  
  735. equipped  with  all  sorts of special mechanisms by which it would query 
  736.  
  737. the layer above and modify its behavior accordingly.  In the  structures 
  738.  
  739. suggested above, in which there is not one but several TCPs, the TCP can 
  740.  
  741. simply  be modified so that it produces the correct behavior as a matter 
  742.  
  743. of course.  This structure has  the  disadvantage  that  there  will  be 
  744.  
  745. several  implementations  of TCP existing on a single machine, which can 
  746.  
  747. mean more maintenance headaches if a problem is found where TCP needs to 
  748.  
  749. be changed.  However, it is probably the case that each of the TCPs will 
  750.  
  751. be substantially simpler  than  the  general  purpose  TCP  which  would 
  752.  
  753. otherwise  have  been  built.    There  are  some  experimental projects 
  754.  
  755. currently under way which suggest that this approach may make  designing 
  756.  
  757. of  a  TCP, or almost any other layer, substantially easier, so that the 
  758.  
  759. total effort involved in bringing up a complete package is actually less 
  760.  
  761. if this approach is followed.  This approach is by  no  means  generally 
  762.  
  763. accepted, but deserves some consideration. 
  764.                                     16 
  765.  
  766.       The  general conclusion to be drawn from this sort of consideration 
  767.  
  768. is that a layer boundary has both a benefit and a penalty.    A  visible 
  769.  
  770. layer  boundary,  with  a  well  specified interface, provides a form of 
  771.  
  772. isolation between two layers which allows one to  be  changed  with  the 
  773.  
  774. confidence  that  the  other  one  will  not  stop  working as a result. 
  775.  
  776. However, a firm layer boundary almost inevitably  leads  to  inefficient 
  777.  
  778. operation.    This  can  easily be seen by analogy with other aspects of 
  779.  
  780. operating systems.  Consider, for example,  file  systems.    A  typical 
  781.  
  782. operating  system  provides  a file system, which is a highly abstracted 
  783.  
  784. representation of a disk.   The  interface  is  highly  formalized,  and 
  785.  
  786. presumed  to  be highly stable.  This makes it very easy for naive users 
  787.  
  788. to have access to  disks  without  having  to  write  a  great  deal  of 
  789.  
  790. software.  The existence of a file system is clearly beneficial.  On the 
  791.  
  792. other  hand,  it is clear that the restricted interface to a file system 
  793.  
  794. almost inevitably leads to inefficiency.  If the interface is  organized 
  795.  
  796. as  a  sequential read and write of bytes, then there will be people who 
  797.  
  798. wish to do high throughput transfers who cannot achieve their goal.   If 
  799.  
  800. the  interface  is  a  virtual  memory  interface, then other users will 
  801.  
  802. regret the necessity of building a byte stream interface on top  of  the 
  803.  
  804. memory  mapped file.  The most objectionable inefficiency results when a 
  805.  
  806. highly sophisticated package, such as a data  base  management  package, 
  807.  
  808. must  be  built  on  top  of  an  existing  operating  system.    Almost 
  809.  
  810. inevitably, the implementors of the database system  attempt  to  reject 
  811.  
  812. the  file  system  and  obtain  direct  access  to the disks.  They have 
  813.  
  814. sacrificed modularity for efficiency. 
  815.  
  816.       The same conflict appears in networking, in a rather extreme  form. 
  817.                                     17 
  818.  
  819.  The concept of a protocol is still unknown and frightening to most naive 
  820.  
  821. programmers.   The idea that they might have to implement a protocol, or 
  822.  
  823. even part of a protocol, as part  of  some  application  package,  is  a 
  824.  
  825. dreadful thought.  And thus there is great pressure to hide the function 
  826.  
  827. of  the  net behind a very hard barrier.  On the other hand, the kind of 
  828.  
  829. inefficiency which results from this is a particularly undesirable  sort 
  830.  
  831. of  inefficiency, for it shows up, among other things, in increasing the 
  832.  
  833. cost of the communications resource used up to achieve  the  application 
  834.  
  835. goal.   In cases where one must pay for one's communications costs, they 
  836.  
  837. usually turn out to be the dominant cost within the system.  Thus, doing 
  838.  
  839. an excessively good job of packaging up the protocols in  an  inflexible 
  840.  
  841. manner  has  a  direct  impact  on  increasing  the cost of the critical 
  842.  
  843. resource within the system.  This is a dilemma which will probably  only 
  844.  
  845. be solved when programmers become somewhat less alarmed about protocols, 
  846.  
  847. so that they are willing to weave a certain amount of protocol structure 
  848.  
  849. into their application program, much as application programs today weave 
  850.  
  851. parts  of  database  management  systems  into  the  structure  of their 
  852.  
  853. application program. 
  854.  
  855.       An extreme example of putting the protocol package  behind  a  firm 
  856.  
  857. layer boundary occurs when the protocol package is relegated to a front- 
  858.  
  859. end processor.  In this case the interface to the protocol is some other 
  860.  
  861. protocol.    It  is  difficult to imagine how to build close cooperation 
  862.  
  863. between layers when they are that far separated.  Realistically, one  of 
  864.  
  865. the prices which must be associated with an implementation so physically 
  866.  
  867. modularized is that the performance will suffer as a result.  Of course, 
  868.  
  869. a separate processor for protocols could be very closely integrated into 
  870.                                     18 
  871.  
  872.  the  mainframe  architecture, with interprocessor co-ordination signals, 
  873.  
  874. shared memory, and similar features.  Such a physical  modularity  might 
  875.  
  876. work  very  well,  but  there  is little documented experience with this 
  877.  
  878. closely coupled architecture for protocol support. 
  879.  
  880.       6.  Efficiency of Protocol Processing 
  881.  
  882.       To this point, this document has considered how a protocol  package 
  883.  
  884. should  be  broken  into  modules,  and  how  those  modules  should  be 
  885.  
  886. distributed between free standing machines, the operating system kernel, 
  887.  
  888. and one or more user processes.  It is now time to  consider  the  other 
  889.  
  890. half  of the efficiency question, which is what can be done to speed the 
  891.  
  892. execution of those programs that actually implement the protocols.    We 
  893.  
  894. will make some specific observations about TCP and IP, and then conclude 
  895.  
  896. with a few generalities. 
  897.  
  898.       IP  is a simple protocol, especially with respect to the processing 
  899.  
  900. of  normal  packets,  so  it  should  be  easy  to  get  it  to  perform 
  901.  
  902. efficiently.    The only area of any complexity related to actual packet 
  903.  
  904. processing has to do with fragmentation and reassembly.  The  reader  is 
  905.  
  906. referred  to  RFC  815,  titled "IP Datagram Reassembly Algorithms", for 
  907.  
  908. specific consideration of this point. 
  909.  
  910.       Most costs in the IP layer come from table look  up  functions,  as 
  911.  
  912. opposed to packet processing functions.  An outgoing packet requires two 
  913.  
  914. translation  functions  to  be  performed.  The internet address must be 
  915.  
  916. translated to a target gateway, and a gateway address must be translated 
  917.  
  918. to a local network number (if the host is  attached  to  more  than  one 
  919.                                     19 
  920.  
  921.  network).    It  is easy to build a simple implementation of these table 
  922.  
  923. look up functions that in fact performs very  poorly.    The  programmer 
  924.  
  925. should  keep  in  mind  that  there may be as many as a thousand network 
  926.  
  927. numbers in a typical configuration.   Linear  searching  of  a  thousand 
  928.  
  929. entry table on every packet is extremely unsuitable.  In fact, it may be 
  930.  
  931. worth  asking  TCP  to  cache  a  hint for each connection, which can be 
  932.  
  933. handed down to IP each time a packet  is  sent,  to  try  to  avoid  the 
  934.  
  935. overhead of a table look up. 
  936.  
  937.       TCP   is   a   more   complex  protocol,  and  presents  many  more 
  938.  
  939. opportunities for getting things wrong.  There  is  one  area  which  is 
  940.  
  941. generally  accepted  as  causing  noticeable and substantial overhead as 
  942.  
  943. part of TCP processing.  This is computation of the checksum.  It  would 
  944.  
  945. be  nice  if this cost could be avoided somehow, but the idea of an end- 
  946.  
  947. to-end checksum is absolutely central to the functioning  of  TCP.    No 
  948.  
  949. host  implementor  should think of omitting the validation of a checksum 
  950.  
  951. on incoming data. 
  952.  
  953.       Various clever tricks have been used to try to minimize the cost of 
  954.  
  955. computing the checksum.  If it is possible to add additional  microcoded 
  956.  
  957. instructions  to the machine, a checksum instruction is the most obvious 
  958.  
  959. candidate.  Since computing the checksum involves picking up every  byte 
  960.  
  961. of the segment and examining it, it is possible to combine the operation 
  962.  
  963. of computing the checksum with the operation of copying the segment from 
  964.  
  965. one  location  to  another.   Since a number of data copies are probably 
  966.  
  967. already required as part of  the  processing  structure,  this  kind  of 
  968.  
  969. sharing might conceivably pay off if it didn't cause too much trouble to 
  970.                                     20 
  971.  
  972.  the  modularity  of  the  program.  Finally, computation of the checksum 
  973.  
  974. seems to be one place where careful attention  to  the  details  of  the 
  975.  
  976. algorithm  used  can  make a drastic difference in the throughput of the 
  977.  
  978. program.  The Multics system provides one of the best  case  studies  of 
  979.  
  980. this,  since  Multics  is  about  as  poorly  organized  to perform this 
  981.  
  982. function as any machine implementing TCP.   Multics  is  a  36-bit  word 
  983.  
  984. machine,  with  four 9-bit bytes per word.  The eight-bit bytes of a TCP 
  985.  
  986. segment are laid down packed in memory, ignoring word boundaries.   This 
  987.  
  988. means  that  when it is necessary to pick up the data as a set of 16-bit 
  989.  
  990. units for the purpose of adding  them  to  compute  checksums,  horrible 
  991.  
  992. masking  and  shifting  is  required  for  each  16-bit value.  An early 
  993.  
  994. version of a program using this  strategy  required  6  milliseconds  to 
  995.  
  996. checksum  a  576-byte  segment.    Obviously,  at  this  point, checksum 
  997.  
  998. computation was becoming the central bottleneck to throughput.   A  more 
  999.  
  1000. careful  recoding of this algorithm reduced the checksum processing time 
  1001.  
  1002. to less than one millisecond.  The strategy used  was  extremely  dirty. 
  1003.  
  1004. It  involved adding up carefully selected words of the area in which the 
  1005.  
  1006. data lay, knowing that for those particular  words,  the  16-bit  values 
  1007.  
  1008. were  properly  aligned  inside  the words.  Only after the addition had 
  1009.  
  1010. been done were the various sums shifted, and finally  added  to  produce 
  1011.  
  1012. the  eventual  checksum.  This kind of highly specialized programming is 
  1013.  
  1014. probably not acceptable if used everywhere within an  operating  system. 
  1015.  
  1016. It is clearly appropriate for one highly localized function which can be 
  1017.  
  1018. clearly identified as an extreme performance bottleneck. 
  1019.  
  1020.       Another area of TCP processing which may cause performance problems 
  1021.  
  1022. is the overhead of examining all of the possible flags and options which 
  1023.                                     21 
  1024.  
  1025.  occur in each incoming packet.  One paper, by Bunch and Day [2], asserts 
  1026.  
  1027. that  the  overhead of packet header processing is actually an important 
  1028.  
  1029. limiting  factor  in  throughput  computation.    Not  all   measurement 
  1030.  
  1031. experiments  have  tended to support this result.  To whatever extent it 
  1032.  
  1033. is true, however, there is an obvious  strategy  which  the  implementor 
  1034.  
  1035. ought  to  use in designing his program.  He should build his program to 
  1036.  
  1037. optimize the expected case.  It is easy, especially when first designing 
  1038.  
  1039. a program, to pay equal attention to all of  the  possible  outcomes  of 
  1040.  
  1041. every test.  In practice, however, few of these will ever happen.  A TCP 
  1042.  
  1043. should  be  built  on the assumption that the next packet to arrive will 
  1044.  
  1045. have absolutely nothing special about it,  and  will  be  the  next  one 
  1046.  
  1047. expected  in  the  sequence  space.   One or two tests are sufficient to 
  1048.  
  1049. determine that the expected set of control flags are on.  (The ACK  flag 
  1050.  
  1051. should be on; the Push flag may or may not be on.  No other flags should 
  1052.  
  1053. be on.)  One test is sufficient to determine that the sequence number of 
  1054.  
  1055. the  incoming  packet  is  one  greater  than  the  last sequence number 
  1056.  
  1057. received.  In almost every case, that will be the actual result.  Again, 
  1058.  
  1059. using the Multics system as an example, failure to optimize the case  of 
  1060.  
  1061. receiving  the  expected  sequence number had a detectable effect on the 
  1062.  
  1063. performance of the system.  The particular problem arose when  a  number 
  1064.  
  1065. of  packets  arrived  at  once.    TCP attempted to process all of these 
  1066.  
  1067. packets before awaking the user.  As a result,  by  the  time  the  last 
  1068.  
  1069. packet  arrived,  there was a threaded list of packets which had several 
  1070.  
  1071. items on it.  When a new packet arrived, the list was searched  to  find 
  1072.  
  1073. the  location  into which the packet should be inserted.  Obviously, the 
  1074.  
  1075. list should be searched from highest sequence number to lowest  sequence 
  1076.                                     22 
  1077.  
  1078.  number,  because  one is expecting to receive a packet which comes after 
  1079.  
  1080. those already received.  By mistake, the list was searched from front to 
  1081.  
  1082. back, starting with the packets with the lowest sequence  number.    The 
  1083.  
  1084. amount of time spent searching this list backwards was easily detectable 
  1085.  
  1086. in the metering measurements. 
  1087.  
  1088.       Other data structures can be organized to optimize the action which 
  1089.  
  1090. is  normally  taken  on  them.  For example, the retransmission queue is 
  1091.  
  1092. very seldom actually used  for  retransmission,  so  it  should  not  be 
  1093.  
  1094. organized  to  optimize that action.  In fact, it should be organized to 
  1095.  
  1096. optimized the discarding of things  from  it  when  the  acknowledgement 
  1097.  
  1098. arrives.    In many cases, the easiest way to do this is not to save the 
  1099.  
  1100. packet  at  all,  but  to  reconstruct  it  only  if  it  needs  to   be 
  1101.  
  1102. retransmitted,  starting  from the data as it was originally buffered by 
  1103.  
  1104. the user. 
  1105.  
  1106.       There is another generality, at least as  important  as  optimizing 
  1107.  
  1108. the  common  case,  which  is  to avoid copying data any more times than 
  1109.  
  1110. necessary.  One more result from the Multics TCP may prove  enlightening 
  1111.  
  1112. here.    Multics takes between two and three milliseconds within the TCP 
  1113.  
  1114. layer to process an incoming packet, depending on its size.  For a  576- 
  1115.  
  1116. byte packet, the three milliseconds is used up approximately as follows. 
  1117.  
  1118. One   millisecond   is   used  computing  the  checksum.    Six  hundred 
  1119.  
  1120. microseconds is spent copying the data.  (The data is copied  twice,  at 
  1121.  
  1122. .3  milliseconds  a copy.)  One of those copy operations could correctly 
  1123.  
  1124. be included as part of the checksum cost, since it is done  to  get  the 
  1125.  
  1126. data  on  a  known  word  boundary  to  optimize the checksum algorithm. 
  1127.                                     23 
  1128.  
  1129.  However,  the  copy also performs another necessary transfer at the same 
  1130.  
  1131. time.  Header processing and packet resequencing takes .7  milliseconds. 
  1132.  
  1133. The  rest  of  the  time  is  used  in miscellaneous processing, such as 
  1134.  
  1135. removing packets from the retransmission queue which are acknowledged by 
  1136.  
  1137. this packet.  Data copying is the second most expensive single operation 
  1138.  
  1139. after data checksuming.   Some  implementations,  often  because  of  an 
  1140.  
  1141. excessively  layered  modularity, end up copying the data around a great 
  1142.  
  1143. deal.  Other implementations end up copying the data because there is no 
  1144.  
  1145. shared memory between processes, and the data must be moved from process 
  1146.  
  1147. to process via a kernel operation.  Unless the amount of  this  activity 
  1148.  
  1149. is  kept  strictly  under  control,  it  will  quickly  become the major 
  1150.  
  1151. performance bottleneck. 
  1152.  
  1153.       7.  Conclusions 
  1154.  
  1155.       This document has addressed two aspects  of  obtaining  performance 
  1156.  
  1157. from a protocol implementation, the way in which the protocol is layered 
  1158.  
  1159. and  integrated  into  the  operating  system,  and the way in which the 
  1160.  
  1161. detailed handling of the packet is optimized.  It would be nice  if  one 
  1162.  
  1163. or  the  other  of these costs would completely dominate, so that all of 
  1164.  
  1165. one's attention could be concentrated there.  Regrettably, this  is  not 
  1166.  
  1167. so.    Depending  on  the particular sort of traffic one is getting, for 
  1168.  
  1169. example, whether Telnet one-byte packets or file transfer  maximum  size 
  1170.  
  1171. packets  at  maximum  speed, one can expect to see one or the other cost 
  1172.  
  1173. being the major bottleneck to throughput.  Most  implementors  who  have 
  1174.  
  1175. studied  their  programs  in  an  attempt to find out where the time was 
  1176.  
  1177. going have reached  the  unsatisfactory  conclusion  that  it  is  going 
  1178.                                     24 
  1179.  
  1180.  equally  to  all parts of their program.  With the possible exception of 
  1181.  
  1182. checksum  processing,  very  few  people  have  ever  found  that  their 
  1183.  
  1184. performance  problems  were  due  to a single, horrible bottleneck which 
  1185.  
  1186. they could fix by a single stroke of inventive programming.  Rather, the 
  1187.  
  1188. performance was something which was improved by  painstaking  tuning  of 
  1189.  
  1190. the entire program. 
  1191.  
  1192.       Most  discussions  of protocols begin by introducing the concept of 
  1193.  
  1194. layering, which tends  to  suggest  that  layering  is  a  fundamentally 
  1195.  
  1196. wonderful  idea  which  should  be  a  part  of  every  consideration of 
  1197.  
  1198. protocols.  In fact, layering is a mixed blessing.    Clearly,  a  layer 
  1199.  
  1200. interface  is  necessary  whenever  more than one client of a particular 
  1201.  
  1202. layer is to be allowed to use  that  same  layer.    But  an  interface, 
  1203.  
  1204. precisely  because  it  is fixed, inevitably leads to a lack of complete 
  1205.  
  1206. understanding as to what one layer wishes to obtain from another.   This 
  1207.  
  1208. has to lead to inefficiency.  Furthermore, layering is a potential snare 
  1209.  
  1210. in  that  one  is  tempted  to think that a layer boundary, which was an 
  1211.  
  1212. artifact of the specification procedure, is in fact the proper  boundary 
  1213.  
  1214. to  use in modularizing the implementation.  Again, in certain cases, an 
  1215.  
  1216. architected layer must correspond to an implemented layer, precisely  so 
  1217.  
  1218. that  several  clients  can  have  access  to that layer in a reasonably 
  1219.  
  1220. straightforward manner.  In other cases, cunning  rearrangement  of  the 
  1221.  
  1222. implemented  module  boundaries to match with various functions, such as 
  1223.  
  1224. the demultiplexing of incoming packets, or the sending  of  asynchronous 
  1225.  
  1226. outgoing  packets,  can  lead  to  unexpected  performance  improvements 
  1227.  
  1228. compared to more traditional implementation strategies.   Finally,  good 
  1229.  
  1230. performance is something which is difficult to retrofit onto an existing 
  1231.                                     25 
  1232.  
  1233.  program.   Since performance is influenced, not just by the fine detail, 
  1234.  
  1235. but by the gross structure, it is sometimes the case that  in  order  to 
  1236.  
  1237. obtain  a  substantial  performance  improvement,  it  is  necessary  to 
  1238.  
  1239. completely redo the program from  the  bottom  up.    This  is  a  great 
  1240.  
  1241. disappointment   to  programmers,  especially  those  doing  a  protocol 
  1242.  
  1243. implementation for  the  first  time.    Programmers  who  are  somewhat 
  1244.  
  1245. inexperienced  and  unfamiliar with protocols are sufficiently concerned 
  1246.  
  1247. with getting their program logically correct that they do not  have  the 
  1248.  
  1249. capacity  to  think  at  the  same  time  about  the  performance of the 
  1250.  
  1251. structure they are building.  Only after they have achieved a  logically 
  1252.  
  1253. correct  program  do they discover that they have done so in a way which 
  1254.  
  1255. has precluded real performance.  Clearly, it is more difficult to design 
  1256.  
  1257. a program thinking from the start about  both  logical  correctness  and 
  1258.  
  1259. performance.  With time, as implementors as a group learn more about the 
  1260.  
  1261. appropriate  structures  to  use  for  building  protocols,  it  will be 
  1262.  
  1263. possible  to  proceed  with  an  implementation  project   having   more 
  1264.  
  1265. confidence  that  the structure is rational, that the program will work, 
  1266.  
  1267. and that the program will work well.    Those  of  us  now  implementing 
  1268.  
  1269. protocols  have the privilege of being on the forefront of this learning 
  1270.  
  1271. process.  It should be no surprise that our  programs  sometimes  suffer 
  1272.  
  1273. from the uncertainty we bring to bear on them. 
  1274.                                     26 
  1275.  
  1276.  Citations 
  1277.  
  1278.       [1]  Cohen  and  Postel,  "On  Protocol  Multiplexing",  Sixth Data 
  1279.  
  1280. Communications Symposium, ACM/IEEE, November 1979. 
  1281.  
  1282.       [2] Bunch and Day, "Control Structure Overhead in TCP", Trends  and 
  1283.  
  1284. Applications:  Computer Networking, NBS Symposium, May 1980. 
  1285.  
  1286.  
  1287.