\documentclass[aspectratio=169,obeyspaces,spaces,hyphens,dvipsnames]{beamer}
\usepackage[utf8]{inputenc}
\usepackage{lmodern}% http://ctan.org/pkg/lm
\usepackage{minted}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{pgfplots}
\usepackage{tikz}
\usepackage[normalem]{ulem}

\mode<presentation>
\usetheme{Bootlin}

\def\signed #1{{\leavevmode\unskip\nobreak\hfil\penalty50\hskip2em
  \hbox{}\nobreak\hfil(#1)
  \parfillskip=0pt \finalhyphendemerits=0 \endgraf}}

\newsavebox\mybox
\newenvironment{aquote}[1]
  {\savebox\mybox{#1}\begin{quotation}}
  {\signed{\usebox\mybox}\end{quotation}}

\title{What's in an Ethernet Driver on Linux ?}
\authors{Maxime Chevallier}
\email{maxime.chevallier@bootlin.com}
\slidesurl{https://bootlin.com/pub/conferences/2024/elc/mastering-ethernet-drivers-linux.pdf}
\institute{Bootlin}
\conference{ELC 2024 - Seattle}

\begin{document}

\addtocontents{toc}{\protect\setcounter{tocdepth}{-1}}
\section{In the Kernel Trenches: Mastering Ethernet Drivers on Linux}
\addtocontents{toc}{\protect\setcounter{tocdepth}{2}}

\begin{frame}{Maxime Chevallier}
  \begin{itemize}
  \item Embedded Linux engineer at Bootlin
    \begin{itemize}
    \item Embedded Linux {\bf expertise}
    \item {\bf Development}, consulting and training
    \item Strong open-source focus
    \end{itemize}
  \item Open-source contributor
  \item Living near {\bf Toulouse}, France
  \end{itemize}
\end{frame}
%
%\begin{frame}[fragile]{Frame with code}
%  \begin{block}{\code{filename}}
%    \fontsize{9}{9}\selectfont
%    \begin{minted}{c}
%#include <stdio.h>
%
%int main(void)
%{
%    printf("hello, world\n");
%}
%    \end{minted}
%  \end{block}
%\end{frame}



\begin{frame}{What is this all about ?}
	\begin{itemize}
		\item Take a look at what Ethernet Drivers do
		\item What are they in charge of ?
		\item Which kernel subsystems and frameworks to they interact with ?
		\item Focus on drivers found on Embedded Systems
			\begin{itemize}
				\item Not the same constraints as a High-Speed Datacented Networking driver
				\item What we will see still applies for these drivers :)
			\end{itemize}
	\end{itemize}
\end{frame}

\section{Ethernet Controller}

\begin{frame}{Ethernet controller - Inside look}
	\begin{itemize}
		\item \code{MII} interface to PHY
		\item \code{MAC} : 802.3 operations (SoF, collision management, flow-control, Idle word, IPG)
		\item \code{Queues} and \code{DMA}
		\item Internal engines : \code{Timestamping}, \code{Filtering}, \code{Parsing}, \code{Encryption}, \code{Switching}...
	\end{itemize}
	\includegraphics[width=\textwidth]{graphics/ethernet_controller_simple.pdf}
\end{frame}

\begin{frame}{\code{struct net_device}}
	\begin{itemize}
		\item Represents a network interface
		\item Backbone of the driver
		\item The \code{.probe()} function of the driver usually registers via \code{netdev_register()}
		\item \code{net_device}s are network \textbf{interfaces}, visible with \code{ip link show}
		\item Each \code{net_device} has it's unique \code{ifindex} within it's namespace (\code{struct net})
		\item netdevs can be part of a hierarchy : \code{lower} and \code{upper} devices
		\item Allocated through \code{(devm_)alloc_etherdev_mqs(priv_size, txqs, rxqs)}
		\item Driver-specific data retrieved using \code{netdev_priv(dev)}
		\item User-visible right after \code{register_netdev()}
	\end{itemize}
\end{frame}

\begin{frame}[fragile]{\code{struct net_device_ops}}
	\begin{itemize}
		 \item Callbacks that the driver exposes to the net core
		 \item Referred to as "NDOs"
		 \item Some are on the data path, some on the control path
		 \item One is mandatory :  
			 \begin{itemize}
				 \item \code{.ndo_start_xmit()}, to transmit data
			 \end{itemize}
		 \item Others might be required depending on the exposed \code{features}
		 \item Specified at init time, \textbf{before registration} :
			 \begin{itemize}
				 \item \code{netdev->netdev_ops = &my_netdev_ops;}
			 \end{itemize}
	\end{itemize}
\end{frame}

\section{Data Path}

\begin{frame}{\code{struct sk_buff}}
	\begin{columns}
		\begin{column}{0.5\textwidth}
			\includegraphics[width=\textwidth]{graphics/skb.pdf}
		\end{column}
		\begin{column}{0.5\textwidth}
			\begin{itemize}
				\item \code{struct sk_buff} (\textbf{s}oc\textbf{k}et \textbf{buff}er)
				\item By convention, pointers to such objects are very often named \code{skb}
				\item Represents a Packet through it's traversal of the kernel networking stack
				\item Created by the Ethernet Driver on RX (\code{build_skb(data, frag_size)})
				\item Consumed on TX (\code{kfree_skb}, \code{dev_kfree_skb_any} and similar)
				\item Can be a simple packet, or a fragmented packet
				\item Contains a data section (payload + headers) and metadata
			\end{itemize}
		\end{column}
	\end{columns}
\end{frame}

\begin{frame}{Page Pool}
	\begin{itemize}
		\item Designed to optimize buffer allocation for DMA transfers
		\item Maintain a pool of memory pages that stays mapped for the device
		\item Allow buffer recycling : \code{skb_mark_for_recycle()}
		\item Prerequisite for XDP, but can be used as-is
		\item Not mandatory, but useful for better performances !
		\item Documentation available at \url{https://docs.kernel.org/networking/page_pool.html}
	\end{itemize}
	If Page Pool isn't used, manual DMA mapping/unmapping for RX/TX must be done.
\end{frame}

\begin{frame}{TX path}
	\begin{itemize}
		\item \code{.ndo_start_xmit()} is called by the core, passing an \code{skb} as a parameter
		\item The driver will create and enqueue DMA descriptors
		\item The driver must take care of sending each fragments and segments
	\end{itemize}
	\begin{itemize}
		\item If supported, the \code{tx queue} on which to enqueue the frame must be retrieved with \code{skb_get_queue_mapping(skb)}
		\item Controllers usually raise an interrupt when a packet has been transmitted
		\item The driver reports how many bytes were sent, for BQL (\href{https://www.bufferbloat.net/projects/}{Bufferbloat})
			\begin{itemize}
				\item \code{netdev(_tx)_send_queue} upon enqueueing
				\item \code{netdev(_tx)_completed_queue} upon completion
			\end{itemize}
		\item The \code{skb} can be released once it's been sent
	\end{itemize}
\end{frame}

\begin{frame}{NAPI}
	\begin{center}
		\sout{\textit{New API}} \textbf{NAPI} means \textbf{NAPI}
	\end{center}
	\begin{itemize}
		\item Process RX packets in budgeted \code{poll} loops after a first packet gets received
		\item \textbf{NAPI Instances} are registered through \code{netif_napi_add()}, passing a \code{poll} callback
			\begin{enumerate}
				\item The fist RX packet raises an interrupt
				\item Driver calls \code{napi_schedule()} and keeps interrupts masked
				\item The \code{poll} callback of a driver is called, with a budget of N packets to process at most
				\item Once N or all packets are processed, the interrupt is re-enabled
			\end{enumerate}
		\item Runs in softirq context, can be switched to threads
		\item Also works for TX, for processing TX completions
		\item There can be multiple NAPI instances (e.g. one per queue)
		\item \url{https://docs.kernel.org/networking/napi.html}
	\end{itemize}
\end{frame}

\begin{frame}{Timestamping}
	\begin{itemize}
		\item Ethernet controllers can have precise timestamping units
		\item Configured through :
			\begin{itemize}
				\item \code{.ndo_hwtstamp_get()} and \code{.ndo_hwtstamp_set()} \textit{(new)}
				\item \code{SIOCGHWTSTAMP} ioctl \textit{(legacy)}
			\end{itemize}
		\item Upon RX, the driver grabs the timestamp from the controller
			\begin{itemize}
				\item Sets it in the skb's \code{struct skb_shared_hwtstamps}
				\item Retrieved using \code{skb_hwtstamps()}
			\end{itemize}
		\item Upon TX, the driver checks \code{skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP}
			\begin{itemize}
				\item If timestamping is possible, set \code{skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;}
				\item call \code{skb_tx_timestamp()} in any case as close to the SKB being sent
				\item call \code{skb_tstamp_tx(skb)} when the timestamp is available
			\end{itemize}
		\item The PHY might also timestamp the packet.
		\item See \url{https://www.kernel.org/doc/html/next/networking/timestamping.html}
	\end{itemize}
\end{frame}

\begin{frame}{Queues - RX}
	\begin{columns}
	\begin{column}{0.25\textwidth}
	\begin{center}
	\includegraphics[width=0.8\textwidth]{graphics/rxqs.pdf}
	\end{center}
	\end{column}
	\begin{column}{0.75\textwidth}
	\begin{itemize}
		\item It's common to have more than one queue per direction
		\item \textbf{RX queues}, often called \code{rxq}
			\begin{itemize}
				\item Ingress traffic is \textbf{steered} towards different queues
				\item \code{rxq} can then be assigned dedicated \code{irq}
				\item \code{per-queue interrupt} can be pinned per-CPU
				\item Needs some hardware packet parsing support
				\item Spread traffic across queues based on a hash : \code{RSS}
				\item Steer individual flows towards dedicated queues : \code{tc}, \code{rxfnc}
			\end{itemize}
	\end{itemize}
	\end{column}
	\end{columns}
\end{frame}

\begin{frame}{Queues - TX}
	\begin{columns}
	\begin{column}{0.25\textwidth}
	\begin{center}
	\includegraphics[width=0.8\textwidth]{graphics/txqs.pdf}
	\end{center}
	\end{column}
	\begin{column}{0.75\textwidth}
	\begin{itemize}
		\item \textbf{TX queues}, often called \code{txq}
			\begin{itemize}
				\item Egress traffic enqueued on several queues
				\item \code{XPS} : eXpress Packet Steering, one queue per CPU
				\item \code{mqprio} : Queues are mapped to priorities
				\item Can then be used for TSN and Time-aware scheduling
				\item Can be used for QoS (DCB VLAN priorisation)
			\end{itemize}
		\item \code{skb_get_queue_mapping()} to retrieve the queue index for an \code{skb}
			\begin{itemize}
				\item Used in \code{.ndo_start_xmit()}
			\end{itemize}
		\item \url{https://docs.kernel.org/networking/scaling.html}
	\end{itemize}
	\end{column}
	\end{columns}
\end{frame}

\begin{frame}{XDP}
	\begin{itemize}
		\item XDP allows running eBPF programs directly at the driver level
		\item Useful for filtering, redirecting, analyzing traffic
		\item XDP is driver-dependent, and requires the driver to use \code{page_pool}
		\item eBPF program gets loaded with \code{.ndo_bpf}
		\item If a program is loaded, run it in the \code{NAPI poll} loop
		\item Dedicated NDO for xmit : \code{.ndo_xdp_xmit}
		\item Documentation at \url{https://docs.cilium.io/en/latest/bpf/progtypes/\#xdp}
		\item Reference driver : \url{https://elixir.bootlin.com/linux/latest/source/drivers/net/ethernet/marvell/mvneta.c}
	\end{itemize}
%dcbnl_ops
\end{frame}

\section{Control Plane}

\begin{frame}{Control Plane}
	\begin{itemize}
		\item Ethernet controllers are highly configurable
		\item Stats reporting at various level (per-queue, MAC, PHY, internal engines)
		\item Offload configuration : Vlan filters, classification, checksumming
		\item Ethernet configuration : MTU, Link speed, Flow control
		\item Some run under \code{rtnl_lock}
			\begin{itemize}
				\item Serializes network configuration
				\item Some ops such as \code{ethtool_ops} must be called under \code{rtnl_lock()}
				\item Unlock with \code{rtnl_unlock()}
				\item Use \code{ASSERT_RTNL()} if your code relies on it being held by the caller
			\end{itemize}
		\item Might still need to be fast !
	\end{itemize}
\end{frame}

\begin{frame}{Entry-points}
	\begin{itemize}
		\item NDOs
			\begin{itemize}
				\item netdev features, TC, MTU configuration, etc.
			\end{itemize}
		\item Other sets of ops in \code{net_device}
			\begin{itemize}
				\item \code{ethtool_ops}, \code{macsec_ops}, ...
				\item Usually set prior to calling \code{register_netdev()}
			\end{itemize}
		\item Notifiers
			\begin{itemize}
				\item Registered hooks : \code{register_netdevice_notifiers}
				\item e.g. switchdev relies on  \code{register_switchdev_notifiers}
				\item Driver decides which notification is relevant for it
			\end{itemize}
		\item Ioctls
			\begin{itemize}
				\item Timestamping (moved to NDO)
				\item PHY control (handled by \code{phylib} and \code{phylink})
				\item Being gradually replaced
			\end{itemize}
		\item Registered anciliary functions
			\begin{itemize}
				\item \code{struct phylink_ops}
				\item \code{struct mii_bus}
				\item \code{struct ptp_clock_info}
			\end{itemize}
	\end{itemize}
\end{frame}

\begin{frame}{NDOs}
	\begin{itemize}
		\item Currently 92 defined ops
		\item Start and Stop the interface
			\begin{itemize}
				\item \code{ip link set eth0 up/down} => \code{.ndo_open() / .ndo_close()} called
			\end{itemize}
		\item Gather stats : \code{.ndo_get_stats64}
		\item Set RX mode (e.g. promisc mode) : \code{.ndo_set_rx_mode()}
		\item Specific features : VFs, Briding, FCoE, VLAN filtering...
	\end{itemize}
\end{frame}

\begin{frame}{netdev features}
	\begin{itemize}
		\item \code{features} represents hardware offload capabilities
			\begin{itemize}
				\item Checksumming, Scatter-gather, segmentation, filtering (mac / vlan)
				\item see \code{ethtool -k <iface>}
				\item attributes of \code{struct net_device}
			\end{itemize}
		\item Drivers set \code{netdev.hw_features} at init, and can also set \code{netdev.features}
			\begin{itemize}
				\item \code{features} : The current active features
				\item \code{hw_features} : Features that can be changed (\textit{hw != hardware})
			\end{itemize}
		\item Users but also the core might want to change the enabled features
			\begin{itemize}
				\item Child devices might require some features to be disabled
			\end{itemize}
		\item \code{.ndo_fix_features()} filters incompatible feature sets for the driver
		\item \code{.ndo_set_features()} applies the new feature set
		\item \url{https://docs.kernel.org/networking/netdev-features.html}
	\end{itemize}
\end{frame}

\begin{frame}{ethtool}
	\begin{itemize}
		\item API to report and control ethernet-specific parameters
		\item These settings and parameters are accessible with \code{ethtool}
		\item Uses a legacy \code{ioctl} interface, superseded by \code{netlink}
		\item Uses a dedicated set of ops : \code{struct ethtool_ops}
		\item \code{netdev->ethtool_ops} are set before driver registration
		\item All \code{ethtool_ops} are optional, and must run under \code{rtnl_lock}
		\item Around 70 different ops
		\item Userspace API : \url{https://docs.kernel.org/networking/ethtool-netlink.html}
	\end{itemize}
\end{frame}

\begin{frame}{\code{struct ethtool_ops}}
	\begin{itemize}
		\item Fine-grained Hardware statistics gathering
		\item Link parameters : Supported modes, flow-control, status, Link-partner, speed, aneg...
		\item Flow classification : Hardware steering to queues, filtering
		\item RSS : Indirection table(s) configuration, key configuration
		\item Channels configuration : Map queues to Interrupts
		\item EEE, FEC, Interrupt Coalescing, WoL, SFP modules, Self-tests, Register dumps...
		\item see \href{https://elixir.bootlin.com/linux/v6.8.6/source/include/linux/ethtool.h\#L818}{\code{struct ethtool_ops} definition}
	\end{itemize}
	\vspace{1cm}
	\textit{More ethtool ops exists for PHY devices}
\end{frame}

\begin{frame}{TC}
	\begin{itemize}
		\item Traffic Control : shaping, policing, scheduling, dropping
		\item Some of the TC operations can be offloaded to Hardware :
	\end{itemize}
	\begin{itemize}
		\item \code{.ndo_setup_tc(netdev, type, *data)} is the main entry-point
		\item \code{type == TC_SETUP_QDISC_MQPRIO}
			\begin{itemize}
				\item Setup the hardware queue prio mapping
				\item Setup per-queue rate-limit
			\end{itemize}
		\item \code{type == TC_SETUP_QDISC_TAPRIO}
			\begin{itemize}
				\item Time Aware per-queue scheduling
			\end{itemize}
		\item \code{type == TC_SETUP_QDISC_CLSFLOWER}
			\begin{itemize}
				\item Flow steering, assigning different RX flows to dedicated queues
			\end{itemize}
		\item \code{type == TC_SETUP_QDISC_CBS}
			\begin{itemize}
				\item Shaping: Limiting transmit speed
			\end{itemize}
		\item Documentation : see \href{https://elixir.bootlin.com/linux/latest/source/net/sched}{the code...}
	\end{itemize}
\end{frame}

\begin{frame}{switchdev}
	% Link to Alex talk
	\begin{itemize}
		\item When the interface is part of an internal switch
		\item The entrypoints are based on \code{notifiers} :
			\begin{itemize}
				\item \code{register_switchdev_notifier}
				\item \code{register_switchdev_blocking_notifier}
			\end{itemize}
		\item The same driver handles multiple ports (one \code{net_device} per port)
		\item Each port should work as a standalone interface at init
		\item \code{bridging} operations are then offloaded
		\item \code{FDB}, \code{MDB}, \code{VLAN} additions and removals are configured into hardware tables
		\item see \url{https://docs.kernel.org/networking/switchdev.html}
	\end{itemize}
\end{frame}

\begin{frame}{Precision Time Protocol}
	\begin{itemize}
		\item For timestamping, Ethernet devices might have internal clocks
		\item These clocks can be synchronized using Precision Time Protocol
		\item \code{linuxptp} provides userspace tools that implements PTP
		\item \code{struct ptp_clock} represents such a clock (PHC)
		\item Dedicated ops for clock configuration : \code{struct ptp_clock_info}
			\begin{itemize}
				\item \code{.adjfine()} to adjust the frequency
				\item \code{.adjtime()} to adjust the time
				\item \code{.get/settime64} to set the time
			\end{itemize}
		\item Clock is registered through \code{ptp_clock_register}
		\item \textbf{timestamping} settings and \textbf{clock} settings are separated
			\begin{itemize}
				\item Timestamping through \code{.ndo_hwtstamp_get/set}
				\item Clock through \code{ptp_clock_info}'s ops
			\end{itemize}
		\item \url{https://docs.kernel.org/driver-api/ptp.html}
	\end{itemize}
\end{frame}

\begin{frame}{Other ops}
	\begin{itemize}
		\item \code{macsec_ops}
			\begin{itemize}
				\item For MACSec (802.1AE) offloading
			\end{itemize}
		\item \code{xfrmdev_ops}
			\begin{itemize}
				\item For IPSec offloading
			\end{itemize}
		\item \code{tlsdev_ops}
			\begin{itemize}
				\item For TLS offloading
			\end{itemize}
		\item \code{dcbnl_ops}
			\begin{itemize}
				\item For DataCenter Bridging offload
			\end{itemize}
	\end{itemize}
\end{frame}

\begin{frame}{PHY}
	\begin{center}
	\includegraphics[height=0.3\textheight]{graphics/ethernet_controller_phy.pdf}
	\end{center}
	\begin{itemize}
		\item Ethernet PHYs are in charge of handling the Layer 1 aspects of a transfer
		\item There exists dedicated chips or IP blocks, which have dedicated drivers
		\item Ethernet drivers need to attach to a PHY, and notify the PHY layer when :
			\begin{itemize}
				\item The PHY should start
				\item The PHY should stop
				\item A few more specific operations such as suspend/resume
			\end{itemize}
		\item The PHY layer will notify the Ethernet driver when the link changes
	\end{itemize}
\end{frame}

\begin{frame}{phylib}
	\begin{itemize}
		\item Framework to write PHY drivers and maintain a PHY's internal state
		\item Out of the scope of this talk
		\item Can be interacted with from Ethernet drivers
		\item \code{struct phy_device} represents an Ethernet PHY
		\item The Ethernet driver is in charge of registering the PHY and attaching to it
		\item In some cases, the Ethernet driver will also act as a MDIO bus driver
			\begin{itemize}
				\item Needs to register a \code{struct mii_bus}
			\end{itemize}
		\item see \url{https://www.kernel.org/doc/html/next/networking/phy.html}
		\item \code{phylink} is now preferred, instead of manually dealing with the PHY
	\end{itemize}
\end{frame}

\begin{frame}{phylink}
	\begin{itemize}
		\item \code{phylink} handles the link between the Ethernet controller and the PHY
		\item The \code{MII} (MAC to PHY) link can sometimes need dynamic reconfiguration
		\item \code{phylink} manages the PHY, using \code{phylib} and deals with it's registration.
		\item \code{phylink} supports \textbf{SFP} cages connection
		\item The Ethernet driver shall provide \code{phylink_mac_ops}
			\begin{itemize}
				\item \code{.mac_link_up() and .mac_link_down()} called depending on the link state
					\begin{itemize}
						\item Established link settings can be configured
						\item \code{speed}, \code{duplex}, \code{pause} settings
					\end{itemize}
				\item \code{.mac_config} called when the link changes:
					\begin{itemize}
						\item \code{phy_interface_t} modification
						\item Autoneg mode : From PHY, Inband or Fixed
					\end{itemize}
			\end{itemize}
		\item \code{phylink_create(cfg, fwnode, interface, ops);} then \code{phylink_of_phy_connect(pl, dn, flags);}
		\item see \url{https://www.kernel.org/doc/html/next/networking/sfp-phylink.html}
	\end{itemize}
\end{frame}

\begin{frame}{PCS}
	\begin{center}
	\includegraphics[height=0.3\textheight]{graphics/ethernet_controller_phy.pdf}
	\end{center}
	\begin{itemize}
		\item Some Ethernet Controllers can have one or more Physical Coding Sublayer blocks
		\item PCS can also sometimes be handled through an external driver
		\item \textbf{phylink} supports dedicated PCS control through \code{struct phylink_pcs}
		\item The \code{phylink_pcs} is either locally crafted, or use dedicated drivers
			\begin{itemize}
				\item Retrieved from the device-tree through \code{pcs-handle}
			\end{itemize}
		\item The Ethernet driver indicates to phylink which PCS to use
			\begin{itemize}
				\item \code{.mac_select_pcs} phylink ops
			\end{itemize}
	\end{itemize}
\end{frame}

\begin{frame}[fragile]{Coding style}
	\begin{columns}
	\begin{column}{0.5\textwidth}
	\begin{itemize}
		\item Comments must be :
	\end{itemize}
		\begin{minted}{c}
/* I am a comment
 * using netdev-style format
 * this is beautiful
 */
		\end{minted}

	\begin{itemize}
		\item and not :
	\end{itemize}
	\begin{minted}{c}
/*
 * I am not a comment
 * using netdev-style format
 */
	\end{minted}
	\end{column}
	\begin{column}{0.5\textwidth}
	\begin{itemize}
		\item Use reverse christmas-tree (RCS) declaration
		\item local variables declaration from longest to shortest \textit{if possible}:
	\end{itemize}
		\vspace{1cm}
	\begin{minted}{c}
struct net_device *dev;
struct sk_buff *skb;
unsigned int rxq;
int err;
	\end{minted}
	\end{column}
	\end{columns}
\end{frame}

\begin{frame}{Contributing}
	\begin{itemize}
		\item Send your patches to the \code{netdev@vger.kernel.org} list (\href{https://lore.kernel.org/netdev/}{lore archive})
		\item Two git trees are maintained :
			\begin{itemize}
				\item net-next : For new features
					\begin{itemize}
						\item \url{https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next.git}
					\end{itemize}
				\item net : For fixes
					\begin{itemize}
						\item \url{https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git}
					\end{itemize}
			\end{itemize}
		\item net-next closes during each merge window (no patches accepted)
			\begin{itemize}
				\item Quick status check here : \url{https://patchwork.hopto.org/net-next.html}
			\end{itemize}
		\item Indicate the tree (net or net-next) your patches target in the subject :
			\begin{itemize}
				\item \code{git format-patch --subject-prefix='PATCH net-next' ...}
			\end{itemize}
		\item Fast-paced development, but high-volume list
		\item Help with reviews can't hurt :)
		\item \url{https://www.kernel.org/doc/html/next/process/maintainer-netdev.html}
	\end{itemize}
\end{frame}

\questionslide

\end{document}
