Enterprise Networking Week 12

Spring 2021, Mondays 5:30-8:00

April 19





Project 5 discussion

UDP implementation

TCP implementation


BBR TCP

How do you assess competing traffic? PROBE_RTT

BWE as max rather than mean

Reno: increase cwnd as a way of probing for more BW
BBR: PROBE_BW. When cwnd < queuesize, MAX feature works to keep increasing cwnd.
cwnd grows 25% every 8 RTTs, or approx 3% per RTT, or faster than Reno as soon as cwnd > 30 packets
As soon as cwnd >= queuesize, the MAX feature works to ensure no further increases.

BBR typically does better when the queue size is not so large

BBR currently sets cwnd to 2*bdp. This leads to huge packet losses if the queue is less than bdp.

As RTTactual increases, BBR's rate (equal to cwnd/RTTactual) falls. Also, as Reno's relative queue utilization grows, BBR's falls. These together are why BBR's throughput falls so precipitously at the start of the Reno-BBR graph. Once the first PROBE_BW event occurs, BBR has a better idea of the actual bandwidth.

MPTCP

SCTP

QUIC

My own TCP

    RCV_NXT: number of next byte we expect to receive; sent in each packet in the ACK field
    SND_NXT: number of next byte we expect to send; sent in each packet in the SEQ field

class tcpsocket methods, used on local side
tcp_handle_packet, used for arriving packets

How do you write this so there is no waiting needed?

tcp_handle_packet and RFC 793

Demo: wireshark traces showing failure at final ACK.

Two Generals and the final ACK

class tcpsocket:
    def __init__(self):
        self.localport=0
        self.remoteport= None
        self.localaddr = None
        self.localaddrb = None
        self.remoteaddr = None
        self.remoteaddrb= None
        self.ipheader = None
        self.tcpheader= None
        self.state = CLOSED
        self.isbound=False
        self.sockettimeout = 0        # in seconds; floating-point value. This is the time a reading socket will wait before throwing a sockettimeout exception.
        self.socknum = nextsocketnum()    # internal identifier
        self.isclosed = False
        self.shadowsocket = None        # The idea was to open "real" sockets with the same port, to reserve it
        self.arrivelist = []            # pkt_bufs that have arrived but cannot yet be ACKed because earlier data has not arrived.
                    # Kept in order of increasing startseq > self.snd_una. May overlap.
                                        # NOT A QUEUE
        self.readqueue = queue.Queue()    # holds pkt_bufs from received packets that have been ACKed, but have not yet been read.
                                        # entries are in order of arrival time; each entry strictly extends read_maxSEQ,
                                        # because otherwise it would be discarded.
        self.read_relSEQ = 1        # Relative seqnum of next byte of data to be read by application; relative offset from beginning of stream
        self.read_maxSEQ = -1        # Seqnum of next byte of data AFTER all data in readqueue

        self.writequeue = queue.Queue() # data (as pkt_buf) that has been written by application, but not yet sent, because of cwnd limits
                                        # Must be strictly non-overlapping
        self.sentqueue = queue.Queue()    # pkt_bufs for packets that have been sent, but not ACKed. Again, must be non-overlapping. Includes SYN/FIN
        self.readevent = None        # we are waiting to read from this socket
        self.connectevent = None    # wait on this until the connection reaches ESTABLISHED. Used for both directions.
        self.connectstatus = 0    # 0 for success; -1 for failure
        self.childsocket = None    # when a connection is accepted, this is the socket. SHOULD REALLY BE A QUEUE.
        self.parentsocket = None    # when we create the child socket, we will eventually need to NOTIFY the parent
        self.lock  = None        # a mutex lock
        self.localISN  = 0        # the one we choose, used for sending
        self.remoteISN = 0        # from other side's arriving SYN, used for *receiving*
        # sender sliding-window parameters. These are all RELATIVE sequence numbers.
        self.snd_una = -1        # smallest unacknowledged sender sequence number; lastACKed +1; bottom of sender window
        self.lastACKed = -1        # deprecated
        self.snd_nxt = -1        # next sequence number we will send, = currentSEQ
        # self.currentSEQ = -1
        self.snd_max = -1        # maximum seq number sent, +1. If packets are lost, snd_next may be less.
        self.cwnd = MIN_CWND        # sending winsize.   
        # receiver sliding-window parameters
        self.remote_adv_wnd = -1    # received advertised winsize, taken from packet window advertisements, max value of cwnd
        self.local_adv_wnd = ADV_WIN    # our own advertised winsize
        self.rcv_wnd = self.local_adv_wnd    # ACTUAL receive winsize; may be reduced. Our own advertised window
        self.rcv_nxt = 0        # next seq# we expect to receive; = current ACK number
        #self.rcv_wup            # highest seq# for which we have actually sent an ACK; <= rcv_nxt.
        self.est_rtt = 0.5
        self.RTO = 2.0            # initial Retransmission TimeOut, in seconds
        self.cwnd = MIN_CWND            #
        self.timeout_time = 0        # time of next packet timeout; incremented on every receive. Set to 0 to disable.
        self.finseqnum   = None    # relative sequence number when we sent our FIN
        self.receivedFIN = False    # did other side send us a FIN?    NOT USED
        self.TWend     = 0        # time TIME_WAIT ends

       

TLS