Network Programming Interfaces · • Potentially allows writing services at a very high level of...

33
Colin Perkins | https://csperkins.org/ | Copyright © 2018 | This work is licensed under the Creative Commons Attribution-NoDerivatives 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nd/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. Network Programming Interfaces Advanced Operating Systems (M) Lecture 7

Transcript of Network Programming Interfaces · • Potentially allows writing services at a very high level of...

Page 1: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018 | This work is licensed under the Creative Commons Attribution-NoDerivatives 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nd/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

Network Programming Interfaces

Advanced Operating Systems (M) Lecture 7

Page 2: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Lecture Outline

• Higher level network programming abstractions • Actors, sockets, and network protocols

• Asynchronous I/O frameworks

• High performance networking

2

Page 3: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Higher level network programming abstractions

3

Page 4: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Message Passing and Network Protocols

• Recap: • Actor-based framework for message passing

• Each actor has a receive loop

• Calls to one function per state

• Messages delivered by runtime system;processed sequentially

• Actor can send messages in reply; return identity of next state

• Can we write network code this way? • Send data by sending a message to an actor representing a socket

• Receive messages representing data received on a socket

4

Message

Message

Message

Message

Mailbox Queue

Dispatcher

Receiver

Dequeue

Process

Done

Request next

Actor

Send to other actors

Receive

Page 5: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Integrating Actors and Sockets

• Conceptually straightforward to integrate actors with network code • Runtime system maintains sending and receiving

threads that manage the sockets

• Receiving thread reads network protocol data from sockets, parses into messages, dispatches into the actor runtime

• Sending thread receives messages from the actor runtime, encodes them as formatted packets of the network protocol, and sends via appropriate socket

5

Message

Message

Message

Message

Receive

Mailbox Queue

Dispatcher

Receiver

Actor

Send to other actors

Network Socket

Parser

Receiving Thread

Sending Thread

Encoder

• Network communication integrated with the actor system as message passing

• Adapters format and parse messages into the wire format

Dequeue

Process

Done

Request next

Page 6: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Parsing and Serialisation

• Parsing and serialisation requires socket awareness of the protocol: • E.g., make Socket an abstract class with encode and parse methods that

are implemented by concrete subclasses and understand particular protocol

• The encode method takes an object representing a protocol message, and returns a byte array that can be sent via the socket

• The parse method takes a byte array received from the socket, and returns an object representing the protocol message

• Encapsulates parsing and serialisation – everything outside the socket uses strongly typed objects, not raw protocol data

6

Page 7: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Actors for Network Programming

• Conceptually clean – the simple message passing model abstracts away details of network transport • Easy to program and debug

• Encapsulates parsing and serialisation

• Helps correctness – on-the-wire format hidden, applications operate on strongly typed objects:

7

def receive = { case HttpRequest(GET, Uri.Path("/ping"), _, _, _) => { sender ! HttpResponse(entity = “PONG”) } case HttpRequest(PUT, …) => { … } case _: Tcp.ConnectionClosed => { … }} (Fragment of Scala+Akka+Spray code)

Page 8: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Actors for Network Programming

• Performance reasonable, but likely not outstanding

• Conceptually well suited to implementing protocols • Asynchronous reception matches network behaviour

• Operates at high level of abstraction

• Examples: EJabberD, WhatsApp → Erlang

• Potentially ill-suited to applications that track details of network behaviour • The “send message and forget it” style isn’t well suited to monitoring the

progress or timing of delivery (e.g., for an adaptive video conference app)

8

Page 9: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Asynchronous I/O Frameworks

• Key insight from actor-based I/O: packet reception should be asynchronous to match the network

• However… • Sending API should be synchronous

• The back pressure of a blocking send is useful to avoid congestion/sending queue build-up

• Applications that query the state of a network interface need to know what is happening now, not what happened some time in the past, after a message exchange

• Much simpler to implement in a synchronous manner

• Actor-based implementations have relatively high overhead

• Implement as blocking event loop, with timeout – an asynchronous (i.e., event driven) I/O framework

9

Page 10: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Event Loops

• Many implementations with broadly similar functionality: • select() and poll(): portable, but

slow with large numbers of sockets

• epool() (Linux), kqueue (FreeBSD/macOS, iOS): efficient, less portable

• libevent/libev/libuv wrap the above in a unified API (libuv currently seems most popular)

• Basic operation: • Pass a set of sockets, file descriptors,

etc., to the kernel

• Poll those for events – will block until something happens or timeout occurs

• Process events, send any responses, loop back for next event

• Single threaded event loop • Long-running operations are passed to

separate worker threads10

Network Socket

Receiver & sender thread

SocketSocketPoll for events

Initialise

Handle events and timeouts

Send response

Page 11: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Example: libev

11

Initialise

Loop, processing events

Callback to handle event and send response if needed

static void udp_cb(EV_P_ ev_io *w, int revents) { // Called with data is readable on the UDP socket}

int main(void) { int port = DEFAULT_PORT; puts("udp_echo server started...");

// Setup a udp listening socket. sd = socket(PF_INET, SOCK_DGRAM, 0); bzero(&addr, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(sd, (struct sockaddr*) &addr, sizeof(addr)) != 0) perror("bind");

// Do the libev stuff. struct ev_loop *loop = ev_default_loop(0); ev_io udp_watcher; ev_io_init(&udp_watcher, udp_cb, sd, EV_READ); ev_io_start(loop, &udp_watcher); ev_loop(loop, 0);

close(sd); return EXIT_SUCCESS;}

Page 12: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Example: Rust MIO

12

Initialise

Loop, processing events

fn main() { let ip = IpAddr::V4(Ipv4Addr::new(0,0,0,0)); let port = 2223; let sockaddr = SocketAddr::new(ip, port); let socket = UdpSocket::bind(&sockaddr).unwrap();

let poll = Poll::new().unwrap(); let mut events = Events::with_capacity(1024);

poll.register(&socket, TOKEN, Ready::readable(), PollOpt::edge()).unwrap();

loop { poll.poll(&mut events, None).unwrap();

for event in &events { match event.token() { TOKEN => { println!("got event"); } _ => panic!("event with unexpected token") } } }}

Handle events

Page 13: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Event Loops

• Asynchronous I/O via event loops – efficient and highly scalable • Some implementations callback based (e.g., libuv), others expose the

event set and allow applications to dispatch (e.g., Rust MIO) • I tend to prefer the latter, pattern matching, style – code is more obvious

• Provided it does no long-running calculations, a single asynchronous I/O thread can usually saturate a single network interface • Use one thread per network interface

• Use a thread pool to handle long-running calculations, passing requests to it for processing

• Model is the same as actor-based systems: • Sequence of events (i.e., messages) delivered to application; process each

in turn, sending replies as needed

• However, have direct access to underlying socket for sending operations, monitoring performance

13

Page 14: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Higher-level Abstractions

• Event-driven asynchronous I/O efficient and flexible → but can lead to obfuscated code • Implementation split across numerous callbacks; hard to follow the logic

• Flexible, to implement complex protocols

• Can we provide an abstraction to simplify common protocol styles? • e.g., a server that responds to a single request with a single response

14

Page 15: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Your Server as a Function (1)

• Conceptually, a server represents a function:

• Takes a request and returns a future – an eventual response or error:

• Combine with parsing and encoding functions:Convert raw protocol data to strongly-typed objects

15

fn service_request(&self, req : Request) -> Future<Response, Error>;

enum Future<Response, Error> { InProgress, Success<Response>, Failed<Error>}

fn parse(&self, data : &[u8]) -> Result<Request, Error>;fn encode(&self, res : Response) -> [u8];

Page 16: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Your Server as a Function (2)

• These three functions, plus definitions of Request, Response, and Error types can specify a server

• Plug into a library handling asynchronous I/O operations/scheduling calls to the functions

• Potentially allows writing services at a very high level of abstraction

• Examples: • Twitter’s Finagle library in Scala

• The Tokio framework for Rust

• Background reading (examinable, but will not be discussed in tutorial): • M. Eriksen, “Your server as a function”, Proceedings of

Workshop on Programming Languages and Operating Systems, Farmington, PA, USA, November 2013. ACM. DOI: 10.1145/2525528.2525538

16

Your Server as a Function

Marius EriksenTwitter Inc.

[email protected]

Abstract

Building server software in a large-scale setting, where systems ex-hibit a high degree of concurrency and environmental variability, isa challenging task to even the most experienced programmer. Ef-ficiency, safety, and robustness are paramount—goals which havetraditionally conflicted with modularity, reusability, and flexibility.

We describe three abstractions which combine to present a pow-erful programming model for building safe, modular, and efficientserver software: Composable futures are used to relate concurrent,asynchronous actions; services and filters are specialized functionsused for the modular composition of our complex server software.

Finally, we discuss our experiences using these abstractions andtechniques throughout Twitter’s serving infrastructure.

Categories and Subject Descriptors D.1.1 [Programming tech-niques]: Applicative (Functional) Programming; D.1.3 [Program-ming techniques]: Concurrent Programming; D.1.3 [Program-ming techniques]: Distributed Programming; C.2.4 [DistributedSystems]: Client/server; C.2.4 [Distributed Systems]: Distributedapplications; D.3.3 [Programming languages]: Language Con-structs and Features—Concurrent programming structures

1. Introduction

Servers in a large-scale setting are required to process tens ofthousands, if not hundreds of thousands of requests concurrently;they need to handle partial failures, adapt to changes in networkconditions, and be tolerant of operator errors. As if that weren’tenough, harnessing off-the-shelf software requires interfacing witha heterogeneous set of components, each designed for a differentpurpose. These goals are often at odds with creating modular andreusable software [6].

We present three abstractions around which we structure ourserver software at Twitter. They adhere to the style of func-tional programming—emphasizing immutability, the compositionof first-class functions, and the isolation of side effects—and com-bine to present a large gain in flexibility, simplicity, ease of reason-ing, and robustness.

Futures The results of asynchronous operations are representedby futures which compose to express dependencies betweenoperations.

Permission to make digital or hard copies of all or part of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage and that copies bear this notice and the full citationon the first page. Copyrights for components of this work owned by others than ACMmust be honored. Abstracting with credit is permitted. To copy otherwise, or republish,to post on servers or to redistribute to lists, requires prior specific permission and/or afee. Request permissions from [email protected] ’13, PLOS’13, November 03-06 2013, Farmington, PA, USA.Copyright c� 2013 ACM 978-1-4503-2460-1/13/11. . . $15.00.http://dx.doi.org/10.1145/2525528.2525538

Services Systems boundaries are represented by asynchronousfunctions called services. They provide a symmetric and uni-form API: the same abstraction represents both clients andservers.

Filters Application-agnostic concerns (e.g. timeouts, retries, au-thentication) are encapsulated by filters which compose to buildservices from multiple independent modules.

Server operations (e.g. acting on an incoming RPC or a time-out) are defined in a declarative fashion, relating the results of the(possibly many) subsequent sub-operations through the use of fu-ture combinators. Operations are phrased as value transformations,encouraging the use of immutable data structures and, we believe,enhancing correctness through simplicity of reasoning.

Operations describe what is computed; execution is handledseparately. This frees the programmer from attending to the minu-tiae of setting up threads, ensuring pools and queues are sized cor-rectly, and making sure that resources are properly reclaimed—these concerns are instead handled by our runtime library, Fina-gle [10]. Relinquishing the programmer from these responsibilities,the runtime is free to adapt to the situation at hand. This is used toexploit thread locality, implement QoS, multiplex network I/O, andto thread through tracing metadata (a la Google Dapper [20]).

We have deployed this in very large distributed systems withgreat success. Indeed, Finagle and its accompanying structuringidioms are used throughout the entire Twitter service stack—fromfrontend web servers to backend data systems.

All of the code examples presented are written in the Scala [17]programming language, though the abstractions work equally well,if not as concisely, in our other principal systems language: Java.

2. Futures

A future is a container used to hold the result of an asynchronousoperation such as a network RPC, a timeout, or a disk I/O opera-tion. A future is either empty—the result is not yet available; suc-ceeded—the producer has completed and has populated the futurewith the result of the operation; or failed—the producer failed, andthe future contains the resulting exception.

An immediately successful future is constructed with Future.value; an immediately failed future with Future.exception. Anempty future is represented by a Promise, which is a writablefuture allowing for at most one state transition, to either of thenonempty states. Promises are similar to I-structures [4], exceptthat they embody failed as well as successful computations; theyare rarely used directly.

Futures compose in two ways. First, a future may be defined asa function of other futures, giving rise to a dependency graph whichis evaluated in the manner of dataflow programming. Second, inde-pendent futures are executed concurrently by default—execution issequenced only where a dependency exists.

Futures are first class values; they are wholly defined in the hostlanguage.

Page 17: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Summary

• Many types of network code are a good fit for actor frameworks • Protocol messages parsed/encoded to/from Actor messages

• But – relatively high overheads; poorly suited to low-level applications

• Event driven asynchronous I/O framework solve many of these issues – but can obfuscate code • Event driven approaches based on pattern matching lead to more obvious

code than callback based systems

• The server-as-a-function approach can abstract asynchronous I/O into simple, high-level, frameworks for some applications

17

Page 18: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

High Performance Networking

18

Page 19: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

High Performance Networking

• Limitations of the kernel protocol stack

• Alternative network stacks

• Accelerating TCP via API improvements

• Some cautionary remarks

19

Page 20: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Network Performance Growth

• Network performance is increasing faster than CPU performance • Chart shows Ethernet bit rate over time

– wireless links follow a similar curve

• Closely tracking exponential growth over time – unlike CPU speed, which stopped growing significantly mid-2000s

• MTU remains constant → packet rate increases • Maximum 14,880,952 packets/second

on 10Gbps Ethernet (scales linearly with link rate)

• Minimum size packet is 60 bytes data, with 8 byte preamble, 4 byte CRC; 12 byte inter-frame gap (silent period) between packets

• CPU cycles available to process each packet decreasing

20

Eth

erne

t bit

rate

(Mbp

s)

0

10000

20000

30000

40000

Date

1990 1994 1998 2002 2006 2010 2014

Page 21: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Limitations of the Kernel Protocol Stack

• Why does the traditional kernel protocol stack offer sub-optimal performance?

• Designed when CPUs were faster than networks • Allocates memory for buffers on per-packet basis

• Copies data multiple times, from NIC (“network interface card”) to kernel to application

• System call to send/receive each packet • Layered architecture offers clean design, but not

efficient packet processing

• Example on right: timing of a sendto() system call on FreeBSD: 950ns total; overheads at each layer boundary due to system call, copies, etc.

• How to redesign the protocol stack to reduce overheads?

21

navigating through buffer chains often exceeds that oflinearizing their content, even when producers do indeedgenerate fragmented packets (e.g. TCP when prependingheaders to data from the socket buffers).

Raw packet I/O: The standard APIs to read/write rawpackets for user programs require at least one memorycopy to move data and metadata between kernel and userspace, and one system call per packet (or, in the bestcases, per batch of packets). Typical approaches involveopening a socket or a Berkeley Packet Filter [14] device,and doing I/O through it using send()/recv() or spe-cialized ioctl() functions.

2.3 Case study: FreeBSD sendto()

To evaluate how time is spent in the processing of apacket, we have instrumented the sendto() system callin FreeBSD2 so that we can force an early return fromthe system call at different depths, and estimate the timespent in the various layers of the network stack. Figure 2shows the results when a test program loops around asendto() on a bound UDP socket. In the table, “time”is the average time per packet when the return point is atthe beginning of the function listed on the row; “delta” isthe difference between adjacent rows, and indicates thetime spent at each stage of the processing chain. As anexample, the userspace code takes 8 ns per iteration, en-tering the kernel consumes an extra 96 ns, and so on.

As we can see, we find several functions at all levelsin the stack consuming a significant share of the total ex-ecution time. Any network I/O (be it through a TCP orraw socket, or a BPF writer) has to go through severalexpensive layers. Of course we cannot avoid the systemcall; the initial mbuf construction/data copy is expensive,and so are the route and header setup, and (surprisingly)the MAC header setup. Finally, it takes a long time totranslate mbufs and metadata into the NIC format. Lo-cal optimizations (e.g. caching routes and headers in-stead of rebuilding them every time) can give modest im-provements, but we need radical changes at all layers togain the tenfold speedup necessary to work at line rateon 10 Gbit/s interfaces.

What we show in this paper is how fast can we becomeif we take such a radical approach, while still enforcingsafety checks on user supplied data through a system call,and providing a libpcap-compatible API.

3 Related (and unrelated) work

It is useful at this point to present some techniques pro-posed in the literature, or used in commercial systems, to

2We expect similar numbers on Linux and Windows.

File Function/description time delta

ns ns

user program sendto 8 96

system call

uipc syscalls.c sys sendto 104

uipc syscalls.c sendit 111

uipc syscalls.c kern sendit 118

uipc socket.c sosend —

uipc socket.c sosend dgram 146 137

sockbuf locking, mbuf

allocation, copyin

udp usrreq.c udp send 273

udp usrreq.c udp output 273 57

ip output.c ip output 330 198

route lookup, ip header

setup

if ethersubr.c ether output 528 162

MAC header lookup and

copy, loopback

if ethersubr.c ether output frame 690

ixgbe.c ixgbe mq start 698

ixgbe.c ixgbe mq start locked 720

ixgbe.c ixgbe xmit 730 220

mbuf mangling, device

programming

– on wire 950

Figure 2: The path and execution times for sendto() ona recent FreeBSD HEAD 64-bit, i7-870 at 2.93 GHz +Turboboost, Intel 10 Gbit NIC and ixgbe driver. Mea-surements done with a single process issuing sendto()calls. Values have a 5% tolerance and are averaged overmultiple 5s tests.

improve packet processing speeds. This will be instru-mental in understanding their advantages and limitations,and to show how our framework can use them.

Socket APIs: The Berkeley Packet Filter, or BPF [14],is one of the most popular systems for direct access toraw packet data. BPF taps into the data path of a net-work device driver, and dispatches a copy of each sent orreceived packet to a file descriptor, from which userspaceprocesses can read or write. Linux has a similar mech-anism through the AF PACKET socket family. BPF cancoexist with regular traffic from/to the system, althoughusually BPF clients put the card in promiscuous mode,causing large amounts of traffic to be delivered to thehost stack (and immediately dropped).

Packet filter hooks: Netgraph (FreeBSD), Netfil-ter (Linux), and Ndis Miniport drivers (Windows) arein-kernel mechanisms used when packet duplication isnot necessary, and instead the application (e.g. a fire-wall) must be interposed in the packet processing chain.These hooks intercept traffic from/to the driver and pass

3

Source: L. Rizzo. netmap: a novel framework for fast packet I/O. In Proceedings of the USENIX Annual Technical Conference, Boston, MA, USA, June 2012.

Page 22: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

An Alternative Network Stack: netmap

• Changes network API – a mechanism to give an application dedicated control of a NIC • A replacement for libpcap, not the Sockets API

• Basis for fast packet capture applications; software router; user-space protocol stack – not general purpose

• Pre-allocate buffers, that are shared between OS and user application; coordinate buffer ownership • No memory allocation at time the packets are sent/received

• No data copies – DMA direct to application accessible memory

• Fewer system calls – one system call can transfer ownership of multiple buffers between application and kernel

• NIC uses efficient DMA to transfer packets to and from memory; kernel manages synchronisation and memory protection • Kernel is the control plane

• NIC and DMA transfer manage the data plane

22

netmap: a novel framework for fast packet I/O

Luigi Rizzo, Universita di Pisa, Italy∗

Proceedings of the 2012 USENIX Annual Technical Conference, June 2012.

https://www.usenix.org/conference/atc12/ †

Abstract

Many applications (routers, traffic monitors, firewalls,etc.) need to send and receive packets at line rate even onvery fast links. In this paper we present netmap, a novelframework that enables commodity operating systemsto handle the millions of packets per seconds traversing1..10 Gbit/s links, without requiring custom hardware orchanges to applications.

In building netmap, we identified and successfully re-duced or removed three main packet processing costs:per-packet dynamic memory allocations, removed bypreallocating resources; system call overheads, amor-tized over large batches; and memory copies, elimi-nated by sharing buffers and metadata between kerneland userspace, while still protecting access to device reg-isters and other kernel memory areas. Separately, someof these techniques have been used in the past. The nov-elty in our proposal is not only that we exceed the perfor-mance of most of previous work, but also that we providean architecture that is tightly integrated with existing op-erating system primitives, not tied to specific hardware,and easy to use and maintain.

netmap has been implemented in FreeBSD and Linuxfor several 1 and 10 Gbit/s network adapters. In our pro-totype, a single core running at 900 MHz can send orreceive 14.88 Mpps (the peak packet rate on 10 Gbit/slinks). This is more than 20 times faster than conven-tional APIs. Large speedups (5x and more) are alsoachieved on user-space Click and other packet forward-ing applications using a libpcap emulation library run-ning on top of netmap.

∗This work was funded by the EU FP7 project CHANGE (257422).†USENIX plans to publish this paper on the Proceedings

of the 2012 USENIX Annual Technical Conference, which willbe available at this URL after June 13, 2012. You mayalso find this paper, with related material, on the author’s site,http://info.iet.unipi.it/ luigi/netmap/

1 Introduction

General purpose OSes provide a rich and flexible envi-ronment for running, among others, many packet pro-cessing and network monitoring and testing tasks. Thehigh rate raw packet I/O required by these applica-tions is not the intended target of general purpose OSes.Raw sockets, the Berkeley Packet Filter [14] (BPF), theAF SOCKET family, and equivalent APIs have beenused to build all sorts of network monitors, traffic gen-erators, and generic routing systems. Performance, how-ever, is inadequate for the millions of packets per sec-ond (pps) that can be present on 1..10 Gbit/s links. Insearch of better performance, some systems (see Sec-tion 3) either run completely in the kernel, or bypass thedevice driver and the entire network stack by exposingthe NIC’s data structures to user space applications. Ef-ficient as they may be, many of these approaches dependon specific hardware features, give unprotected access tohardware, or are poorly integrated with the existing OSprimitives.

The netmap framework presented in this paper com-bines and extends some of the ideas presented in thepast trying to address their shortcomings. Besides givinghuge speed improvements, netmap does not depend onspecific hardware1, has been fully integrated in FreeBSDand Linux with minimal modifications, and supports un-modified libpcap clients through a compatibility library.

One metric to evaluate our framework is performance:in our implementation, moving one packet between thewire and the userspace application has an amortized costof less than 70 CPU clock cycles, which is at least oneorder of magnitude faster than standard APIs. In otherwords, a single core running at 900 MHz can source orsink the 14.88 Mpps achievable on a 10 Gbit/s link. Thesame core running at 150 MHz is well above the capacity

1netmap can give isolation even without hardware mechanisms suchas IOMMU or VMDq, and is orthogonal to hardware offloading andvirtualization mechanisms (checksum, TSO, LRO, VMDc, etc.)

1

L. Rizzo. netmap: a novel framework for fast packet I/O. In Proceedings of the USENIX Annual Technical Conference, Boston, MA, USA, June 2012. https://www.usenix.org/conference/atc12/technical-sessions/presentation/rizzo (paper and video of presentation)

Page 23: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Shared Ownership of NIC Buffers (1)

• Modern NICs maintain circular buffers sized to hold queues of full size packets • NIC writes incoming packets direct to

one segment of ring buffer via DMA

• Operating system copies from other segment into lower layer of protocol stack – first of several copies

• If using netmap → OS disconnected; ownership of ring buffer segment is temporarily granted to application to process packets in place

• (Analogous for outgoing packets)

23

Ownership granted to application

Ownership maintained by NIC and DMA

Page 24: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Shared Ownership of NIC Buffers (2)

24

distinctive feature of netmap is the attempt to design andimplement an API that is simple to use, tightly integratedwith existing OS mechanisms, and not tied to a specificdevice or hardware features.

netmap achieves its high performance through severaltechniques:

• a lightweight metadata representation which is com-pact, easy to use, and hides device-specific fea-tures. Also, the representation supports processingof large number of packets in each system call, thusamortizing its cost;

• linear, fixed size packet buffers that are preallocatedwhen the device is opened, thus saving the cost ofper-packet allocations and deallocations;

• removal of data-copy costs by granting applicationsdirect, protected access to the packet buffers. Thesame mechanism also supports zero-copy transferof packets between interfaces;

• support of useful hardware features (such as multi-ple hardware queues).

Overall, we use each part of the system for the task it isbest suited to: the NIC to move data quickly between thenetwork and memory, and the OS to enforce protectionand provide support for synchronization.

hoststack

NIC rings

netmap API

Application

netmaprings

network adapter

Figure 3: In netmap mode, the NIC rings are discon-nected from the host network stack, and exchange pack-ets through the netmap API. Two additional netmap ringslet the application talk to the host stack.

At a very high level, when a program requests to putan interface in netmap mode, the NIC is partially dis-connected (see Figure 3) from the host protocol stack.The program gains the ability to exchange packets withthe NIC and (separately) with the host stack, throughcircular queues of buffers (netmap rings) implementedin shared memory. Traditional OS primitives such as

indexflags len

ring_size

cur

buf_ofs

flags

avail

num_rings

ring_ofs[]pkt_buf

pkt_buf

pkt_buf

pkt_buf

netmap_if netmap ringsphy_addrlen

NIC ring

Figure 4: User view of the shared memory area exportedby netmap.

select()/poll() are used for synchronization. Apartfrom the disconnection in the data path, the operatingsystem is unaware of the change so it still continues touse and manage the interface as during regular operation.

4.1 Data structures

The key component in the netmap architecture are thedata structures shown in Figure 4. They are designedto provide the following features: 1) reduced/amortizedper-packet overheads; 2) efficient forwarding betweeninterfaces; 3) efficient communication between the NICand the host stack; and 4) support for multi-queueadapters and multi core systems.

netmap supports these features by associating to eachinterface three types of user-visible objects, shown inFigure 4: packet buffers, netmap rings, and netmap if

descriptors. All objects for all netmap-enabled interfacesin the system reside in the same memory region, allo-cated by the kernel in a non-pageable area, and sharedby all user processes. The use of a single region is con-venient to support zero-copy forwarding between inter-faces, but it is trivial to modify the code so that differentinterfaces or groups of interfaces use separate memoryregions, gaining better isolation between clients.

Since the shared memory is mapped by processes andkernel threads in different virtual address spaces, anymemory reference contained in that region must use rel-

ative addresses, so that pointers can be calculated in aposition-independent way. The solution to this problemis to implement references as offsets between the parentand child data structures.

Packet buffers have a fixed size (2 Kbytes in the cur-rent implementation) and are shared by the NICs anduser processes. Each buffer is identified by a unique in-

dex, that can be easily translated into a virtual address byuser processes or by the kernel, and into a physical ad-dress used by the NIC’s DMA engines. Buffers for allnetmap rings are preallocated when the interface is put

5

Source: L. Rizzo. netmap: a novel framework for fast packet I/O. In Proceedings of the USENIX Annual Technical Conference, Boston, MA, USA, June 2012.

pkt_buf objects form the circular buffer, and are in memory shared between NIC and application

netmap_ring provides index into the circular buffer; tracks current ownership of each pkt_buf

netmap_if provides metadata about the interface

Page 25: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Sample netmap Code

25

struct netmap_if *nifp;struct nmreq req;int i, len;char *buf;

fd = open("/dev/netmap", 0);strcpy(req.nr_name, "ix0"); // register the interfaceioctl(fd, NIOCREG, &req); // offset of the structuremem = mmap(NULL, req.nr_memsize, PROT_READ|PROT_WRITE, 0, fd, 0);nifp = NETMAP_IF(mem, req.nr_offset);for (;;) {

struct pollfd x[1];struct netmap_ring *ring = NETMAP_RX_RING(nifp, 0);

x[0].fd = fd;x[0].events = POLLIN;poll(x, 1, 1000);for ( ; ring->avail > 0 ; ring->avail--) {

i = ring->cur;buf = NETMAP_BUF(ring, i);use_data(buf, ring->slot[i].len);ring->cur = NETMAP_NEXT(ring, i);

}}

Updates netmap_ring structure, based on the received data (ring->cur and ring->avail only, no data copied, no synchronisation)

Gets pointer to shared pkf_buf

Page 26: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Benefits and Limitations of netmap

• Memory shared between NIC and application • Misbehaving applications can read memory owned by

NIC – see unpredictable contents since DMA active in this region

• Kernel data structures are protected – cannot crash the kernel or see other kernel data

• Operates on granularity of network interface • Application has access to all traffic on netmap interface

• Limited applicability – not a replacement for the TCP/IP stack, but well suited to network monitoring or software router implementation

• Performance excellent – saturates 10Gbps Ethernet sending minimum size packets on 900MHz CPU • Using minimum size packets requires highest packet

rate → highest overhead

• Similar performance receiving packets

26

but we want it to be as simple as possible in order toreduce the interference on the measurement. Our ini-tial tests then use two very simple programs that makeapplication costs almost negligible: a packet generatorwhich streams pre-generated packets, and a packet re-ceiver which just counts incoming packets.

5.2 Test equipment

We have run most of our experiments on systemsequipped with an i7-870 4-core CPU at 2.93 GHz(3.2 GHz with turbo-boost), memory running at1.33 GHz, and a dual port 10 Gbit/s card based on theIntel 82599 NIC. The numbers reported in this paperrefer to the netmap version in FreeBSD HEAD/amd64as of April 2012. Experiments have been run using di-rectly connected cards on two similar systems. Resultsare highly repeatable (within 2% or less) so we do notreport confidence intervals in the tables and graphs.

netmap is extremely efficient so it saturates a 10 Gbit/sinterface even at the maximum packet rate, and we needto run the system at reduced clock speeds to determinethe performance limits and the effect of code changes.Our systems can be clocked at different frequencies,taken from a discrete set of values. Nominally, most ofthem are multiples of 150 MHz, but we do not know howprecise the clock speeds are, nor the relation betweenCPU and memory/bus clock speeds.

The transmit speed (in packets per second) has beenmeasured with a packet generator similar to the one inSection 4.2.3. The packet size can be configured at run-time, as well as the number of queues and threads/coresused to send/receive traffic. Packets are prepared in ad-vance so that we can run the tests with close to zero per-byte costs. The test program loops around a poll(), send-ing at most B packets (batch size) per ring at each round.On the receive side we use a similar program, except thatthis time we poll for read events and only count packets.

5.3 Transmit speed versus clock rate

As a first experiment we ran the generator with variableclock speeds and number of cores, using a large batchsize so that the system call cost is almost negligible. Bylowering the clock frequency we can determine the pointwhere the system becomes CPU bound, and estimate the(amortized) number of cycles spent for each packet.

Figure 5 show the results using 1..4 cores andan equivalent number of rings, with 64-byte packets.Throughput scales quite well with clock speed, reach-ing the maximum line rate near 900 MHz with 1 core.This corresponds to 60-65 cycles/packet, a value whichis reasonably in line with our expectations. In fact, in this

0

2

4

6

8

10

12

14

16

0 0.5 1 1.5 2 2.5 3T

x R

ate

(M

pps)

Clock speed (GHz)

netmap on 4 coresnetmap on 2 coresnetmap on 1 core

Linux/pktgenFreeBSD/netsend

Figure 5: Netmap transmit performance with 64-bytepackets, variable clock rates and number of cores, com-pared to pktgen (a specialised, in-kernel generator avail-able on linux, peaking at about 4 Mpps) and a netsend(FreeBSD userspace, peaking at 1.05 Mpps).

particular test, the per-packet work is limited to validat-ing the content of the slot in the netmap ring and updatingthe corresponding slot in the NIC ring. The cost of cachemisses (which do exist, especially on the NIC ring) isamortized among all descriptors that fit into a cache line,and other costs (such as reading/writing the NIC’s regis-ters) are amortized over the entire batch.

Once the system reaches line rate, increasing the clockspeed reduces the total CPU usage because the generatorsleeps until an interrupt from the NIC reports the avail-ability of new buffers. The phenomenon is not linear anddepends on the duration of the interrupt mitigation in-tervals. With one core we measured 100% CPU load at900 MHz, 80% at 1.2 GHz and 55% at full speed.

Scaling with multiple cores is reasonably good, butthe numbers are not particularly interesting because thereare no significant contention points in this type of ex-periment, and we only had a small number of operatingpoints (1..4 cores, 150,300, 450 Mhz) before reachinglink saturation.

Just for reference, Figure 5 also reports the maximumthroughput of two packet generators representative of theperformance achievable using standard APIs. The lineat the bottom represents netsend, a FreeBSD userspaceapplication running on top of a raw socket. netsendpeaks at 1.05 Mpps at the highest clock speed. Figure 2details how the 950 ns/pkt are spent.

The other line in the graph is pktgen, an in-kernelpacket generator available in Linux, which reaches al-most 4 Mpps at maximum clock speed, and 2 Mpps at1.2 GHz (the minimum speed we could set in Linux).Here we do not have a detailed profile of how time isspent, but the similarity of the device drivers and the ar-chitecture of the application suggest that most of the cost

9

Source: L. Rizzo. netmap: a novel framework for fast packet I/O. In Proceedings of the USENIX Annual Technical Conference, Boston, MA, USA, June 2012.

Page 27: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

StackMap: Accelerating TCP with netmap

• Key insight: the TCP/IP stack processing is not expensive – inefficiencies are primarily system call overheads, copying data, and Socket API limitations with large number of file descriptors

• The netmap framework avoids the copies and reduces number of system calls, and gains in performance – but without the TCP/IP stack

• StackMap integrates the Linux kernel TCP/IP stack with netmap • Uses kernel TCP/IP stack for the control plane

• Uses netmap for the data plane – new API

• Like netmap, requires a dedicated network interface for each StackMap enabled application

27

USENIX Association 2016 USENIX Annual Technical Conference 43

StackMap: Low-Latency Networking with the OS Stack and Dedicated NICs

Kenichi Yasukata†1, Michio Honda2, Douglas Santry2, and Lars Eggert21Keio University

2NetApp

AbstractStackMap leverages the best aspects of kernel-bypass

networking into a new low-latency Linux network servicebased on the full-featured TCP kernel implementation, bydedicating network interfaces to applications and offeringan extended version of the netmap API as a zero-copy, low-overhead data path while retaining the socket API for thecontrol path. For small-message, transactional workloads,StackMap outperforms baseline Linux by 4 to 80 % inlatency and 4 to 391 % in throughput. It also achievescomparable performance with Seastar, a highly-optimizeduser-level TCP/IP stack for DPDK.

1 IntroductionThe TCP/IP protocols are typically implemented as part ofan operating system (OS) kernel and exposed to applica-tions through an application programming interface (API)such as the socket API [61] standard. This protects andisolates applications from one another and allows the OSto arbitrate access to network resources. Applications canfocus on implementing their specific higher-level func-tionality and need not deal with the details of networkcommunication.

A shared kernel implementation of TCP/IP has otheradvantages. The commercialization of the Internet hasrequired continuous improvements to end-to-end datatransfers. A collaboration between commercial and opensource developers, researchers and IETF participants overat least the last 25 years has been improving TCP/IP toscale to increasingly diverse network characteristics [11,39, 58], growing traffic volumes [13, 32], and improvedtolerance to throughput fluctuations and reduced transmis-sion latencies [1, 10, 49].

A modern TCP/IP stack is consequently a complex,highly optimized and analyzed piece of software. Due tothese complexities, only a small number of stacks (e.g.,

†Most of the research was done during an internship at NetApp.

Linux, Windows, Apple, BSD) have a competitive featureset and performance, and therefore push the vast majorityof traffic. Because of this relatively small number of OSstacks (compared to the number of applications), TCP/IPimprovements have a well-understood and relatively easydeployment path via kernel updates, without the need tochange applications.

However, implementing TCP/IP in the kernel also hasdownsides, which are becoming more pronounced withlarger network capacities and applications that are moresensitive to latency and jitter. Kernel data processingand queueing delays now dominate end-to-end latencies,particularly over uncongested network paths. For example,the fabric latency across a datacenter network is typicallyonly a few µs. But a minimal HTTP transaction over thesame fabric, consisting of a short “GET” request and an“OK” reply, takes tens to hundreds of µs (see Section 3).

Several recent proposals attempt to avoid these over-heads in a radical fashion: they bypass the kernel stack andinstead implement all TCP/IP processing inside the appli-cation in user space [24, 29, 37] or in a virtual machinecontext [4]. Although successful in avoiding overheads,these kernel-bypass proposals also do away with manyof the benefits of a shared TCP/IP implementation: Theyusually implement a simplistic flavor of TCP/IP that doesnot include many of the performance optimizations of theOS stacks, it is unclear if and by whom future protocol im-provements would be implemented and deployed, and thedifferent TCP/IP versions used by different applicationsmay negatively impact one another in the network.

It is questionable whether kernel-bypass approachesare suitable even for highly specialized network environ-ments such as datacenters. Due to economic reasons [17],they are assembled from commodity switches and do notfeature a centralized flow scheduler [2, 45]. Therefore,path characteristics in such datacenters vary, and moreadvanced TCP protocol features may be useful in order toguarantee sub-millisecond flow completion times.

1

K. Yasukata, M. Honda, D. Santry, and L. Eggert. StackMap: Low-latency networking with the OS stack and dedicated NICs. In Proceedings of the USENIX Annual Technical Conference, Denver, CO, USA, June 2016. https://www.usenix.org/conference/atc16/technical-sessions/presentation/yasukata

Page 28: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

StackMap Architecture

• Socket API for control: socket(), bind(), listen(), accept(), etc.

• Netmap API used for data • STACKMAP_BUF() updates netmap’s

circular buffer, and passes data through the TCP/IP stack for processing

• StackMap manages the buffer pool • Circular buffer used by netmap

• If packet must be stored for retransmission, its buffer is swapped out of the netmap ring and replaced by another from the pool, until needed

• Zero copy – just swaps pointers; buffer is already shared between netmap, kernel, and application

• Also manages scratchpad data structure, to simplify iteration over data from on multiple connections

28

48 2016 USENIX Annual Technical Conference USENIX Association

A second design principle is retaining isolation: al-though StackMap assumes that applications are privileged(they see all traffic on dedicated NICs), it must still pro-tect the OS and any other applications when a privilegedStackMap application crashes. StackMap inherits most ofits protection mechanisms from netmap, which it is basedon, including protection of NIC registers and exclusivering buffer operations between the kernel and user space.We discuss the limitations posed by our current prototypein Section 6.

A third design principle is backwards compatibility:when a NIC is dedicated to a StackMap application, reg-ular applications must remain able to use other NICs.StackMap achieves this by retaining part of the socket APIfor control plane operations. Since today’s commodityOSes mostly use monolithic kernels, StackMap must sharea single network stack instance across all NICs, whetherthey are dedicated to privileged applications or sharedby regular applications. One implication of this designprinciple is that it makes a complete shared-nothing designdifficult, i.e., some coordination remains required. How-ever, Section 5 shows that this coordination overhead issmall. Additionally, the OS stack is increasingly being dis-aggregated into shared objects, such as accept queues, andStackMap will benefit from such improvements directly,further improving future performance.

4.2 StackMap ArchitectureThe StackMap design centers around combining a fastpacket I/O framework with the OS TCP/IP stack, to giveapplication fast message-oriented communication overTCP connections, which has been crucial for the applica-tions like memcached, web servers and content deliverynetwork (CDN) servers, to name a few [7, 22]. Thus, inaddition to dedicating NICs to privileged applications,StackMap must also enable the kernel stack to apply itsregular TCP/IP processing to those NICs. To this end,StackMap extends the netmap framework to allow it toefficiently integrate with the OS stack.

DPDK is not a suitable basis for StackMap, becauseit executes its NIC drivers entirely in user space. It isdifficult to efficiently have such user-space NIC driverscall into the kernel network stack.

Although netmap already supports communicating withthe OS stack [54], its current method has significantoverheads, because it is unoptimized and only focuses onapplications that use the socket API, which as we haveshown to have undesirable overheads.

Figure 2 illustrates the StackMap architecture.StackMap (i) mediates traffic between a dedicated NICand a privileged application through a slightly extendedversion of the netmap API; (ii) uses the kernel TCP/IPstack to process incoming TCP packets and send outgoing

StackMap

StackMap App.

User

Kern

el

Socket API

TCP/IP/Ethernet

netmap Framework/API

Stack port

OS Packet I/O

NIC port

Regular App.

Drivers, NICs NIC ringsNIC rings

Data pathControl path

rings/slots

Buffer pool

Figure 2: StackMap architecture overview.

application data; (iii) and uses the regular socket API forcontrol, to both share the protocol/port-number space withregular applications and to present a consistent picture ofclients and connections to the kernel.

For the data path API, the goal of StackMap is tocombine the efficiency, generality and security of thenetmap packet I/O framework with the full-fledged kernelTCP/IP implementation, to give applications a way tosend and receive messages over TCP with much loweroverheads compared to the socket API.

These performance benefits will require an applicationto more carefully manage and segment the data it ishandling. However, we believe that this is an acceptabletrade-off, at least for transactional applications that careabout message latencies rather than bulk throughput. Inaddition, because StackMap retains the socket API forcontrol purposes, an application can also still use thestandard data plane syscalls e.g., read() and write()(with the usual associated overheads).

4.3 Netmap OverviewNetmap [54] maintains several pools of uniquely-indexed,pre-allocated packet buffers inside the kernel. Some ofthese buffers are referenced by slots, which are containedin rings. A set of rings forms a port. A NIC port mapsits rings to NIC hardware rings for direct packet bufferaccess (Figure 2). A pipe port provides a zero-copy point-to-point IPC channel [53]; a VALE port is a virtual NIC ofa VALE/mSwitch [23, 56] software switch instance (notshown in Figure 2).

The netmap API provides a common interface to alltypes of ports. It defines methods to manipulate rings anduses poll() and ioctl() syscalls for synchronizationwith the kernel, whose backend performs port-specificoperations, e.g., device I/O for NIC ports or packet for-warding for VALE ports. Netmap buffers that are partof the same pool are interchangeable between slots, evenacross different rings or ports, which enables zero-copyoperations.

Source: K. Yasukata, M. Honda, D. Santry, and L. Eggert. StackMap: Low-latency networking with the OS stack and dedicated NICs. In Proceedings of the USENIX Annual Technical Conference, Denver, CO, USA, June 2016.

Page 29: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

StackMap API

29

50 2016 USENIX Annual Technical Conference USENIX Association

1 struct sockaddr_in sin = { AF_INET, "10.0.0.1", INADDR_ANY };2 int sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);3 bind(sd, &sin);4 // prefix “stack” opens stack port for given interface5 struct nm_desc ∗nmd = nm_open("stack:ix0");6 connect(sd, dst_addr); /∗ non-blocking ∗/7 // transmit using ring 0 only, for this example8 struct netmap_ring ∗ring = NETMAP_TXRING(nmd->nifp, 0);9 uint32_t cur = ring->cur;

10 while (app_has_data && cur != ring->tail) {11 struct netmap_slot ∗slot = &ring->slot[cur];12 char ∗buf = STACKMAP_BUF(ring, slot->buf_index);13 // place payload in buf, then14 slot->fd = sd;15 cur = nm_ring_next(ring, cur);16 }17 ring->head = ring->cur = cur;18 ioctl(nmd->fd, NIOCTXSYNC);

Figure 4: Initiating a connection and sending data.

4.5 StackMap APIIn order to share the kernel TCP/IP stack with regularapplications, StackMap retains the socket API for control,including, e.g., the socket(), bind(), listen() andaccept() syscalls. To reduce connection setup costs,StackMap optionally can perform accept() in the kernelbefore returning to user space, similar to MegaPipe [22].

The StackMap data path API has been designed to re-semble the netmap API, except for a few extensions. Oneis the STACKMAP_BUF(slot_idx, ring) macro, whichextends the netmap NETMAP_BUF(slot_idx, ring)macro and returns a pointer to the beginning of the pay-load data in a packet buffer. STACKMAP_BUF allows anapplication to easily write and read payload data to andfrom buffers, skipping the packet headers (which on TXare filled in by the kernel).

On TX, the application must indicate the descriptor foreach slot to be transmitted, so that the OS stack can identifythe respective TCP connections. On RX, the OS stackmarks the slots accordingly, so that the application canidentify which connection the data belongs to. Figure 4illustrates use of the StackMap API for opening a newTCP connection and sending data in C-like pseudo code.

On RX, an application can consume data by simplytraversing the RX ring of a stack port. However, thissimple approach often does not integrate naturally intoexisting applications, because they are written to iter-ate over descriptors or connections, rather than iteratingover data in packet arrival order. Unfortunately, usingthe epoll_wait() syscall is not an option because ofsignificant overheads shown in Section 3.2.

StackMap thus introduces a new API that allows ap-plications to consume data more naturally, ordered bydescriptor. It is based on constructing a list of ready filedescriptors during network stack processing, as well asgrouping buffers for each descriptor, and by exploiting theopportunity that the application synchronously calls intothe kernel network stack.

fd3 fd4fd6 fd4fd4fd3fd62536

0123456

Next slot

Slot index

01

35

4 6

head tailStack port RX ring Scratchpad

[fd3][fd4]

[fd6][fd5]

Descriptor Array

fd3fd4

fd6

[0][1][2]

Figure 5: Algorithm to build an array of ready descriptors.

Figure 5 illustrates this algorithm with an example.Here, the OS stack has identified packets 0, 2 and 3 tobelong to file descriptor 4 (fd4), packets 1 and 5 belong tofd3, and packets 4 and 6 to fd6. Note that descriptors areguaranteed to be unique per process. Each slot maintainsa “next slot” index that points to the next slot of the samedescriptor. StackMap uses a scratchpad table indexedby descriptor to maintain the head and tail slot index foreach. The tail is used by the OS stack to append newdata to a particular descriptor, by setting the “next slot”of the last packet to this descriptor, without having totraverse the ring. The head is used by the application tofind the first packet for a particular descriptor, also withouthaving to traverse the ring. This algorithm is inspired bymSwitch [23], and we expect similarly high performanceand scalability.

The scratchpad is a process-wide data structure whichrequires 32 B (for two 16 B buffer indices) per entry,and usually holds 1024 entries (the default per-processmaximum number of descriptors in Linux). We do notconsider the resulting size of 32 KB problematic on today’ssystems even if it was extended by one or two orders ofmagnitude, but it would be possible to reduce this furtherby dynamically managing the scratchpad (which wouldincur some modest overhead).

When the first data for a particular descriptor is ap-pended, StackMap also places the descriptor into a de-scriptor array (see Figure 5) that is exposed to the applica-tion. The application uses this array very similarly to howit would use the array returned by epoll_wait(), butwithout incurring the overhead of that syscall. Figure 6illustrates how an application receives data and traversesthe RX ring by descriptor.

The current API allows an application to traverse anRX ring both in packet-arrival order (i.e., without usingthe descriptor array) and in descriptor order. In the future,StackMap may sort buffers in descriptor order whenmoving them into the stack port RX ring. This wouldremove the ability to traverse in packet order, but greatlysimplifies the API and eliminates the need for exportingthe descriptor array and scratchpad to user space.

4.6 StackMap ImplementationIn order to validate the StackMap architecture, we imple-mented it in the Linux 4.2 kernel with netmap support.

8

Source: K. Yasukata, M. Honda, D. Santry, and L. Eggert. StackMap: Low-latency networking with the OS stack and dedicated NICs. In Proceedings of the USENIX Annual Technical Conference, Denver, CO, USA, June 2016.

Sockets API used to initiate connectionThe netmap API is used to send and receive data

The STACKMAP_BUF() call is an extension that passes the data to the kernel TCP/IP stack, handles ACKs, retransmission, congestion control, etc.

Page 30: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

StackMap Performance

• Linux with StackMap extensions outperforms standard Linux

• Primary benefits are avoiding copies and better scaling with concurrent flows: performance benefit increases with response size and number of connections

• Note: uses the full kernel TCP/IP stack – not a cut-down version – benefits due to new API, not reduced functionality

30

USENIX Association 2016 USENIX Annual Technical Conference 53

� �� �� �� �� ���

����������������

���������� ��� �����������

�������������

� �� �� �� �� ���

����������������

���������� ��� �����������

� �� �� �� �� ���

����������������

���������� ��� �����������

64 B Response Size 512 B Response Size 1280 B Response Size

Figure 7: Mean and 99th percentile round-trip latencies (top row), mean number of ready descriptors in each eventprocessing cycle (middle row) and throughputs (bottom row), with the number of concurrent TCP connections (horizontalaxis) for different response sizes (64, 512 and 1280 B).

Figure 8: Memcached latency and throughput results.

on 1024 B objects. While still simple, memcached has aslightly more complex application logic than the simpleHTTP server we used for the previous benchmarks, andtherefore exhibits higher processing delays (see Table 2).

Figure 8 shows mean latencies with standard deviations,as well as aggregate throughputs. StackMap achievessignificantly higher throughputs and lower latencies thanLinux, as well as a much smaller latency variance. This issimilar to observations earlier in this section. Surprisingly,StackMap also slightly outperforms Seastar.

5.5 Memcached Multicore ScalabilityFinally, we evaluate multi-core scalability with StackMap,again using memcached as an application, and comparesthe results against Linux and Seastar. The object size for

Figure 9: Memcached multi-core throughput.

this experiment is 64 B to prevent the network from becom-ing saturated. In order to investigate the overheads andscalability of memcached itself, we also compare againstthe simple HTTP server used for our other measurements,configured to also serve 64 B messages.

Figure 9 shows aggregate throughputs when using adifferent number of CPU cores to serve the workload. Upto six cores used, the relative performance differencesbetween Linux, Seastar and StackMap remain similar,with Linux being slowest, and StackMap slightly outper-forming Seastar. However, Seastar begins to outperformthe others at eight cores. StackMap and Linux retain theirrelative performance difference. This is to be expected,because the current StackMap implementation does notyet optimize locking when the Linux TCP/IP operates inStackMap mode, nor has memcached been modified toremove such locks when used with StackMap. In contrast,Seastar adopts a shared-nothing design, and memcachedon top of Seastar also has been highly optimized formulti-core scalability. The inclusion of the simple HTTPserver results for StackMap attempt to illustrate its scal-

11

Page 31: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Accelerating TCP: Other Approaches

• Numerous other attempts to accelerate TCP/IP stack processing exist: • Example: sandstorm builds on netmap; combines

application, TCP/IP, and ethernet processing into a user-space library – builds highly optimised, special purpose, protocol stack for each application (see “Network Stack Specialization for Performance”)

• Example: Google’s QUIC protocol aims to provide an alternative to TCP, with better performance, in a user space protocol running over UDP

• …

• No clear consensus on the right approach • API changes to batch packet processing and reduce

copies are clearly beneficial – how general purpose the resulting API needs to be is unclear

• Pervasive encryption may reduce the benefits – you need to make a copy while decrypting, and many of these approaches benefit from zero-copy stacks

31

Network Stack Specialization for Performance

Ilias MarinosUniversity of Cambridge

[email protected]

Robert N.M. WatsonUniversity of Cambridge

[email protected]

Mark HandleyUniversity College [email protected]

AbstractContemporary network stacks are masterpieces of generality, sup-porting many edge-node and middle-node functions. Generalitycomes at a high performance cost: current APIs, memory models,and implementations drastically limit the effectiveness of increas-ingly powerful hardware. Generality has historically been requiredso that individual systems could perform many functions. How-ever, as providers have scaled services to support millions of users,they have transitioned toward thousands (or millions) of dedicatedservers, each performing a few functions. We argue that the over-head of generality is now a key obstacle to effective scaling, makingspecialization not only viable, but necessary.

We present Sandstorm and Namestorm, web and DNS serversthat utilize a clean-slate userspace network stack that exploits knowl-edge of application-specific workloads. Based on the netmap frame-work, our novel approach merges application and network-stackmemory models, aggressively amortizes protocol-layer costs basedon application-layer knowledge, couples tightly with the NIC eventmodel, and exploits microarchitectural features. Simultaneously, theservers retain use of conventional programming frameworks. Wecompare our approach with the FreeBSD and Linux stacks usingthe nginx web server and NSD name server, demonstrating 2–10⇥and 9⇥ improvements in web-server and DNS throughput, lowerCPU usage, linear multicore scaling, and saturated NIC hardware.

Categories and Subject DescriptorsC.2.1 [Computer-Communication Networks]: Network Architec-ture and Design — Network communications

General Terms: Design, performance

Keywords: Network stacks; network performance; network-stack specialization; clean-slate design

1. INTRODUCTIONConventional network stacks were designed in an era where indi-

vidual systems had to perform multiple diverse functions. In the last

Permission to make digital or hard copies of all or part of this work for personal orclassroom use is granted without fee provided that copies are not made or distributedfor profit or commercial advantage and that copies bear this notice and the full citationon the first page. Copyrights for components of this work owned by others than ACMmust be honored. Abstracting with credit is permitted. To copy otherwise, or republish,to post on servers or to redistribute to lists, requires prior specific permission and/or afee. Request permissions from [email protected]’14, August 17–22, 2014, Chicago, Illinois, USA.Copyright 2014 ACM 978-1-4503-2836-4/14/08 ...$15.00.http://dx.doi.org/10.1145/2619239.2626311.

decade, the advent of cloud computing and the ubiquity of network-ing has changed this model; today, large content providers servehundreds of millions of customers. To scale their systems, they areforced to employ many thousands of servers, with each providingonly a single network service. Yet most content is still served withconventional general-purpose network stacks.

These general-purpose stacks have not stood still, but today’sstacks are the result of numerous incremental updates on top of code-bases that were originally developed in the early 1990s. Arguably,these network stacks have proved to be quite efficient, flexible, andreliable, and this is the reason that they still form the core of contem-porary networked systems. They also provide a stable programmingAPI, simplifying software development. But this generality comeswith significant costs, and we argue that the overhead of generalityis now a key obstacle to effective scaling, making specialization notonly viable, but necessary.

In this paper we revisit the idea of specialized network stacks.In particular, we develop Sandstorm, a specialized userspace stackfor serving static web content, and Namestorm, a specialized stackimplementing a high performance DNS server. More importantly,however, our approach does not simply shift the network stack touserspace: we also promote tight integration and specialization ofapplication and stack functionality, achieving cross-layer optimiza-tions antithetical to current design practices.

Servers such as Sandstorm could be used for serving images suchas the Facebook logo, as OCSP [20] responders for certificate revo-cations, or as front end caches to popular dynamic content. This isa role that conventional stacks should be good at: nginx [6] uses thesendfile() system call to hand over serving static content to theoperating system. FreeBSD and Linux then implement zero-copystacks, at least for the payload data itself, using scatter-gather to di-rectly DMA the payload from the disk buffer cache to the NIC. Theyalso utilize the features of smart network hardware, such as TCPSegmentation Offload (TSO) and Large Receive Offload (LRO) tofurther improve performance. With such optimizations, nginx doesperform well, but as we will demonstrate, a specialized stack canoutperform it by a large margin.

Namestorm is aimed at handling extreme DNS loads, such asmight be seen at the root nameservers, or when a server is undera high-rate DDoS attack. The open-source state of the art here isNSD [5], which combined with a modern OS that minimizes datacopies when sending and receiving UDP packets, performs well.Namestorm, however, can outperform it by a factor of nine.

Our userspace web server and DNS server are built uponFreeBSD’s netmap [31] framework, which directly maps the NICbuffer rings to userspace. We will show that not only is it possible fora specialized stack to beat nginx, but on data-center-style networkswhen serving small files typical of many web pages, it can achieve

175

I. Marinos, R. N. M. Watson, and M. Handley. Network stack specialization for performance. Proceedings of the SIGCOMM Conference, Chicago, IL, USA, August 2014. ACM. DOI: 10.1145/2619239.2626311 (Open access via http://dl.acm.org/authorize?N71202)

Page 32: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Conclusions

• Improvements to network performance relative to CPU performance highlight limitations of Sockets API for high performance – ongoing work to find good new APIs

• Beware: it’s very hard to beat TCP – incredibly well tuned, secure, and well maintained • TCP highly optimised over many years – handles edge cases in security and

congestion control that are non-obvious • IETF RFC 7414 (“A Roadmap for TCP Specification Documents”) is 55 pages, and

references 150 other documents – textbook explanations of TCP omit much important detail

• Likely better to optimise kernel TCP stack and API, than end up stuck on a poorly maintained user-space stack

32

Page 33: Network Programming Interfaces · • Potentially allows writing services at a very high level of abstraction • Examples: • Twitter’s Finagle library in Scala • The Tokio

Colin Perkins | https://csperkins.org/ | Copyright © 2018

Further Reading – For Tutorial

33

netmap: a novel framework for fast packet I/O

Luigi Rizzo, Universita di Pisa, Italy∗

Proceedings of the 2012 USENIX Annual Technical Conference, June 2012.

https://www.usenix.org/conference/atc12/ †

Abstract

Many applications (routers, traffic monitors, firewalls,etc.) need to send and receive packets at line rate even onvery fast links. In this paper we present netmap, a novelframework that enables commodity operating systemsto handle the millions of packets per seconds traversing1..10 Gbit/s links, without requiring custom hardware orchanges to applications.

In building netmap, we identified and successfully re-duced or removed three main packet processing costs:per-packet dynamic memory allocations, removed bypreallocating resources; system call overheads, amor-tized over large batches; and memory copies, elimi-nated by sharing buffers and metadata between kerneland userspace, while still protecting access to device reg-isters and other kernel memory areas. Separately, someof these techniques have been used in the past. The nov-elty in our proposal is not only that we exceed the perfor-mance of most of previous work, but also that we providean architecture that is tightly integrated with existing op-erating system primitives, not tied to specific hardware,and easy to use and maintain.

netmap has been implemented in FreeBSD and Linuxfor several 1 and 10 Gbit/s network adapters. In our pro-totype, a single core running at 900 MHz can send orreceive 14.88 Mpps (the peak packet rate on 10 Gbit/slinks). This is more than 20 times faster than conven-tional APIs. Large speedups (5x and more) are alsoachieved on user-space Click and other packet forward-ing applications using a libpcap emulation library run-ning on top of netmap.

∗This work was funded by the EU FP7 project CHANGE (257422).†USENIX plans to publish this paper on the Proceedings

of the 2012 USENIX Annual Technical Conference, which willbe available at this URL after June 13, 2012. You mayalso find this paper, with related material, on the author’s site,http://info.iet.unipi.it/ luigi/netmap/

1 Introduction

General purpose OSes provide a rich and flexible envi-ronment for running, among others, many packet pro-cessing and network monitoring and testing tasks. Thehigh rate raw packet I/O required by these applica-tions is not the intended target of general purpose OSes.Raw sockets, the Berkeley Packet Filter [14] (BPF), theAF SOCKET family, and equivalent APIs have beenused to build all sorts of network monitors, traffic gen-erators, and generic routing systems. Performance, how-ever, is inadequate for the millions of packets per sec-ond (pps) that can be present on 1..10 Gbit/s links. Insearch of better performance, some systems (see Sec-tion 3) either run completely in the kernel, or bypass thedevice driver and the entire network stack by exposingthe NIC’s data structures to user space applications. Ef-ficient as they may be, many of these approaches dependon specific hardware features, give unprotected access tohardware, or are poorly integrated with the existing OSprimitives.

The netmap framework presented in this paper com-bines and extends some of the ideas presented in thepast trying to address their shortcomings. Besides givinghuge speed improvements, netmap does not depend onspecific hardware1, has been fully integrated in FreeBSDand Linux with minimal modifications, and supports un-modified libpcap clients through a compatibility library.

One metric to evaluate our framework is performance:in our implementation, moving one packet between thewire and the userspace application has an amortized costof less than 70 CPU clock cycles, which is at least oneorder of magnitude faster than standard APIs. In otherwords, a single core running at 900 MHz can source orsink the 14.88 Mpps achievable on a 10 Gbit/s link. Thesame core running at 150 MHz is well above the capacity

1netmap can give isolation even without hardware mechanisms suchas IOMMU or VMDq, and is orthogonal to hardware offloading andvirtualization mechanisms (checksum, TSO, LRO, VMDc, etc.)

1 USENIX Association 2016 USENIX Annual Technical Conference 43

StackMap: Low-Latency Networking with the OS Stack and Dedicated NICs

Kenichi Yasukata†1, Michio Honda2, Douglas Santry2, and Lars Eggert21Keio University

2NetApp

AbstractStackMap leverages the best aspects of kernel-bypass

networking into a new low-latency Linux network servicebased on the full-featured TCP kernel implementation, bydedicating network interfaces to applications and offeringan extended version of the netmap API as a zero-copy, low-overhead data path while retaining the socket API for thecontrol path. For small-message, transactional workloads,StackMap outperforms baseline Linux by 4 to 80 % inlatency and 4 to 391 % in throughput. It also achievescomparable performance with Seastar, a highly-optimizeduser-level TCP/IP stack for DPDK.

1 IntroductionThe TCP/IP protocols are typically implemented as part ofan operating system (OS) kernel and exposed to applica-tions through an application programming interface (API)such as the socket API [61] standard. This protects andisolates applications from one another and allows the OSto arbitrate access to network resources. Applications canfocus on implementing their specific higher-level func-tionality and need not deal with the details of networkcommunication.

A shared kernel implementation of TCP/IP has otheradvantages. The commercialization of the Internet hasrequired continuous improvements to end-to-end datatransfers. A collaboration between commercial and opensource developers, researchers and IETF participants overat least the last 25 years has been improving TCP/IP toscale to increasingly diverse network characteristics [11,39, 58], growing traffic volumes [13, 32], and improvedtolerance to throughput fluctuations and reduced transmis-sion latencies [1, 10, 49].

A modern TCP/IP stack is consequently a complex,highly optimized and analyzed piece of software. Due tothese complexities, only a small number of stacks (e.g.,

†Most of the research was done during an internship at NetApp.

Linux, Windows, Apple, BSD) have a competitive featureset and performance, and therefore push the vast majorityof traffic. Because of this relatively small number of OSstacks (compared to the number of applications), TCP/IPimprovements have a well-understood and relatively easydeployment path via kernel updates, without the need tochange applications.

However, implementing TCP/IP in the kernel also hasdownsides, which are becoming more pronounced withlarger network capacities and applications that are moresensitive to latency and jitter. Kernel data processingand queueing delays now dominate end-to-end latencies,particularly over uncongested network paths. For example,the fabric latency across a datacenter network is typicallyonly a few µs. But a minimal HTTP transaction over thesame fabric, consisting of a short “GET” request and an“OK” reply, takes tens to hundreds of µs (see Section 3).

Several recent proposals attempt to avoid these over-heads in a radical fashion: they bypass the kernel stack andinstead implement all TCP/IP processing inside the appli-cation in user space [24, 29, 37] or in a virtual machinecontext [4]. Although successful in avoiding overheads,these kernel-bypass proposals also do away with manyof the benefits of a shared TCP/IP implementation: Theyusually implement a simplistic flavor of TCP/IP that doesnot include many of the performance optimizations of theOS stacks, it is unclear if and by whom future protocol im-provements would be implemented and deployed, and thedifferent TCP/IP versions used by different applicationsmay negatively impact one another in the network.

It is questionable whether kernel-bypass approachesare suitable even for highly specialized network environ-ments such as datacenters. Due to economic reasons [17],they are assembled from commodity switches and do notfeature a centralized flow scheduler [2, 45]. Therefore,path characteristics in such datacenters vary, and moreadvanced TCP protocol features may be useful in order toguarantee sub-millisecond flow completion times.

1

K. Yasukata, M. Honda, D. Santry, and L. Eggert. StackMap: Low-latency networking with the OS stack and dedicated NICs. In Proceedings of the USENIX Annual Technical Conference, Denver, CO, USA, June 2016. https://www.usenix.org/conference/atc16/technical-sessions/presentation/yasukata

L. Rizzo. netmap: a novel framework for fast packet I/O. In Proceedings of the USENIX Annual Technical Conference, Boston, MA, USA, June 2012. https://www.usenix.org/conference/atc12/technical-sessions/presentation/rizzo (paper and video of presentation)