home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / rfc / 800s / rfc817.txt < prev    next >
Text File  |  1992-09-22  |  46KB  |  1,389 lines

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