All of lore.kernel.org
 help / color / mirror / Atom feed
From: Leonard Crestez <cdleonard@gmail.com>
To: David Ahern <dsahern@kernel.org>, Shuah Khan <shuah@kernel.org>,
	Dmitry Safonov <0x7f454c46@gmail.com>,
	Eric Dumazet <edumazet@google.com>
Cc: "David S. Miller" <davem@davemloft.net>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	Kuniyuki Iwashima <kuniyu@amazon.co.jp>,
	Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org>,
	Jakub Kicinski <kuba@kernel.org>,
	Yuchung Cheng <ycheng@google.com>,
	Francesco Ruggeri <fruggeri@arista.com>,
	Mat Martineau <mathew.j.martineau@linux.intel.com>,
	Christoph Paasch <cpaasch@apple.com>,
	Ivan Delalande <colona@arista.com>,
	Priyaranjan Jha <priyarjha@google.com>,
	netdev@vger.kernel.org, linux-crypto@vger.kernel.org,
	linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 10/25] selftests: tcp_authopt: Test key address binding
Date: Mon,  1 Nov 2021 18:34:45 +0200	[thread overview]
Message-ID: <4b4f69bb41c21af41c9c8b8c9e2d939980d33ec2.1635784253.git.cdleonard@gmail.com> (raw)
In-Reply-To: <cover.1635784253.git.cdleonard@gmail.com>

By default TCP-AO keys apply to all possible peers but it's possible to
have different keys for different remote hosts.

This patch adds initial tests for the behavior behind the
TCP_AUTHOPT_KEY_BIND_ADDR flag. Server rejection is tested via client
timeout so this can be slightly slow.

Signed-off-by: Leonard Crestez <cdleonard@gmail.com>
---
 .../tcp_authopt_test/netns_fixture.py         |  85 ++++++++++
 .../tcp_authopt/tcp_authopt_test/server.py    | 124 ++++++++++++++
 .../tcp_authopt/tcp_authopt_test/test_bind.py | 155 ++++++++++++++++++
 .../tcp_authopt/tcp_authopt_test/utils.py     | 114 +++++++++++++
 4 files changed, 478 insertions(+)
 create mode 100644 tools/testing/selftests/tcp_authopt/tcp_authopt_test/netns_fixture.py
 create mode 100644 tools/testing/selftests/tcp_authopt/tcp_authopt_test/server.py
 create mode 100644 tools/testing/selftests/tcp_authopt/tcp_authopt_test/test_bind.py
 create mode 100644 tools/testing/selftests/tcp_authopt/tcp_authopt_test/utils.py

diff --git a/tools/testing/selftests/tcp_authopt/tcp_authopt_test/netns_fixture.py b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/netns_fixture.py
new file mode 100644
index 000000000000..9c10fafd8694
--- /dev/null
+++ b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/netns_fixture.py
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: GPL-2.0
+import socket
+import subprocess
+from ipaddress import IPv4Address, IPv6Address
+
+from .conftest import raise_skip_no_netns
+
+
+class NamespaceFixture:
+    """Create a pair of namespaces connected by one veth pair
+
+    Each end of the pair has multiple addresses but everything is in the same subnet
+    """
+
+    server_netns_name = "tcp_authopt_test_server"
+    client_netns_name = "tcp_authopt_test_client"
+
+    @classmethod
+    def get_ipv4_addr(cls, ns=1, index=1) -> IPv4Address:
+        return IPv4Address("10.10.0.0") + (ns << 8) + index
+
+    @classmethod
+    def get_ipv6_addr(cls, ns=1, index=1) -> IPv6Address:
+        return IPv6Address("fd00::") + (ns << 16) + index
+
+    @classmethod
+    def get_addr(cls, address_family=socket.AF_INET, ns=1, index=1):
+        if address_family == socket.AF_INET:
+            return cls.get_ipv4_addr(ns, index)
+        elif address_family == socket.AF_INET6:
+            return cls.get_ipv6_addr(ns, index)
+        else:
+            raise ValueError(f"Bad address_family={address_family}")
+
+    # 02:* means "locally administered"
+    server_mac_addr = "02:00:00:00:00:01"
+    client_mac_addr = "02:00:00:00:00:02"
+
+    ipv4_prefix_len = 16
+    ipv6_prefix_len = 64
+
+    @classmethod
+    def get_prefix_length(cls, address_family) -> int:
+        return {
+            socket.AF_INET: cls.ipv4_prefix_len,
+            socket.AF_INET6: cls.ipv6_prefix_len,
+        }[address_family]
+
+    def __init__(self, **kw):
+        raise_skip_no_netns()
+        for k, v in kw.items():
+            setattr(self, k, v)
+
+    def __enter__(self):
+        self._del_netns()
+        script = f"""
+set -e
+ip netns add {self.server_netns_name}
+ip netns add {self.client_netns_name}
+ip link add veth0 netns {self.server_netns_name} type veth peer name veth0 netns {self.client_netns_name}
+ip netns exec {self.server_netns_name} ip link set veth0 up addr {self.server_mac_addr}
+ip netns exec {self.client_netns_name} ip link set veth0 up addr {self.client_mac_addr}
+"""
+        for index in [1, 2, 3]:
+            script += f"ip -n {self.server_netns_name} addr add {self.get_ipv4_addr(1, index)}/16 dev veth0\n"
+            script += f"ip -n {self.client_netns_name} addr add {self.get_ipv4_addr(2, index)}/16 dev veth0\n"
+            script += f"ip -n {self.server_netns_name} addr add {self.get_ipv6_addr(1, index)}/64 dev veth0 nodad\n"
+            script += f"ip -n {self.client_netns_name} addr add {self.get_ipv6_addr(2, index)}/64 dev veth0 nodad\n"
+        subprocess.run(script, shell=True, check=True)
+        return self
+
+    def _del_netns(self):
+        script = f"""\
+set -e
+if ip netns list | grep -q {self.server_netns_name}; then
+    ip netns del {self.server_netns_name}
+fi
+if ip netns list | grep -q {self.client_netns_name}; then
+    ip netns del {self.client_netns_name}
+fi
+"""
+        subprocess.run(script, shell=True, check=True)
+
+    def __exit__(self, *a):
+        self._del_netns()
diff --git a/tools/testing/selftests/tcp_authopt/tcp_authopt_test/server.py b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/server.py
new file mode 100644
index 000000000000..4cad2d61093b
--- /dev/null
+++ b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/server.py
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: GPL-2.0
+import logging
+import os
+import selectors
+import socket
+import typing
+from contextlib import ExitStack
+from threading import Thread
+
+logger = logging.getLogger(__name__)
+
+
+class SimpleServerThread(Thread):
+    """Simple server thread for testing TCP sockets
+
+    All data is read in 1000 bytes chunks and either echoed back or discarded.
+
+    :ivar _listen_socket_list: List of listen sockets, not for direct manipulation.
+    :ivar server_socket: List of accepted sockets.
+    :ivar keep_half_open: do not close in response to remote close.
+    """
+
+    DEFAULT_BUFSIZE = 1000
+    _listen_socket_list: typing.List[socket.socket]
+    server_socket: typing.List[socket.socket]
+    sel: typing.Optional[selectors.BaseSelector]
+
+    def __init__(
+        self,
+        sockarg: typing.Union[None, socket.socket, typing.List[socket.socket]] = None,
+        mode="recv",
+        bufsize=DEFAULT_BUFSIZE,
+        keep_half_open=False,
+    ):
+        if isinstance(sockarg, socket.socket):
+            self._listen_socket_list = [sockarg]
+        elif isinstance(sockarg, list):
+            self._listen_socket_list = sockarg
+        elif sockarg is None:
+            self._listen_socket_list = []
+        else:
+            raise TypeError(f"Bad sockarg={sockarg!r}")
+        self.server_socket = []
+        self.bufsize = bufsize
+        self.keep_half_open = keep_half_open
+        self.mode = mode
+        self.sel = None
+        super().__init__()
+
+    def _read(self, conn, events):
+        # logger.debug("events=%r", events)
+        try:
+            data = conn.recv(self.bufsize)
+        except ConnectionResetError:
+            # logger.info("reset %r", conn)
+            conn.close()
+            self.sel.unregister(conn)
+            return
+        # logger.debug("len(data)=%r", len(data))
+        if len(data) == 0:
+            if not self.keep_half_open:
+                # logger.info("closing %r", conn)
+                conn.close()
+                self.sel.unregister(conn)
+        else:
+            if self.mode == "echo":
+                conn.sendall(data)
+            elif self.mode == "recv":
+                pass
+            else:
+                raise ValueError(f"Unknown mode {self.mode}")
+
+    def _stop_pipe_read(self, conn, events):
+        self.should_loop = False
+
+    def start(self) -> None:
+        self.exit_stack = ExitStack()
+        self._stop_pipe_rfd, self._stop_pipe_wfd = os.pipe()
+        self.exit_stack.callback(lambda: os.close(self._stop_pipe_rfd))
+        self.exit_stack.callback(lambda: os.close(self._stop_pipe_wfd))
+        self.sel = self.exit_stack.enter_context(selectors.DefaultSelector())
+        self.sel.register(
+            self._stop_pipe_rfd,
+            selectors.EVENT_READ,
+            self._stop_pipe_read,
+        )
+        for sock in self._listen_socket_list:
+            self.sel.register(sock, selectors.EVENT_READ, self._accept)
+        self.should_loop = True
+        return super().start()
+
+    def _accept(self, sock, events):
+        # logger.info("accept on %r", sock)
+        conn, _addr = sock.accept()
+        conn = self.exit_stack.enter_context(conn)
+        conn.setblocking(False)
+        self.sel.register(conn, selectors.EVENT_READ, self._read)
+        self.server_socket.append(conn)
+
+    def add_listen_socket(self, sock):
+        self._listen_socket_list.append(sock)
+        if self.sel:
+            self.sel.register(sock, selectors.EVENT_READ, self._accept)
+
+    def run(self):
+        # logger.debug("loop init")
+        while self.should_loop:
+            for key, events in self.sel.select(timeout=1):
+                callback = key.data
+                callback(key.fileobj, events)
+        # logger.debug("loop done")
+
+    def stop(self):
+        """Try to stop nicely"""
+        os.write(self._stop_pipe_wfd, b"Q")
+        self.join()
+        self.exit_stack.close()
+
+    def __enter__(self):
+        self.start()
+        return self
+
+    def __exit__(self, *args):
+        self.stop()
diff --git a/tools/testing/selftests/tcp_authopt/tcp_authopt_test/test_bind.py b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/test_bind.py
new file mode 100644
index 000000000000..73074535c9ca
--- /dev/null
+++ b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/test_bind.py
@@ -0,0 +1,155 @@
+# SPDX-License-Identifier: GPL-2.0
+"""Test TCP-AO keys can be bound to specific remote addresses"""
+import socket
+from contextlib import ExitStack
+
+import pytest
+
+from .conftest import skipif_missing_tcp_authopt
+from .linux_tcp_authopt import (
+    TCP_AUTHOPT_ALG,
+    TCP_AUTHOPT_FLAG,
+    TCP_AUTHOPT_KEY_FLAG,
+    set_tcp_authopt,
+    set_tcp_authopt_key,
+    tcp_authopt,
+    tcp_authopt_key,
+)
+from .netns_fixture import NamespaceFixture
+from .server import SimpleServerThread
+from .utils import (
+    DEFAULT_TCP_SERVER_PORT,
+    check_socket_echo,
+    create_listen_socket,
+    netns_context,
+)
+
+pytestmark = skipif_missing_tcp_authopt
+
+
+@pytest.mark.parametrize("address_family", [socket.AF_INET, socket.AF_INET6])
+def test_addr_server_bind(exit_stack: ExitStack, address_family):
+    """ "Server only accept client2, check client1 fails"""
+    nsfixture = exit_stack.enter_context(NamespaceFixture())
+    server_addr = str(nsfixture.get_addr(address_family, 1, 1))
+    client_addr = str(nsfixture.get_addr(address_family, 2, 1))
+    client_addr2 = str(nsfixture.get_addr(address_family, 2, 2))
+
+    # create server:
+    listen_socket = exit_stack.push(
+        create_listen_socket(family=address_family, ns=nsfixture.server_netns_name)
+    )
+    exit_stack.enter_context(SimpleServerThread(listen_socket, mode="echo"))
+
+    # set keys:
+    server_key = tcp_authopt_key(
+        alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+        key="hello",
+        flags=TCP_AUTHOPT_KEY_FLAG.BIND_ADDR,
+        addr=client_addr2,
+    )
+    set_tcp_authopt(
+        listen_socket,
+        tcp_authopt(flags=TCP_AUTHOPT_FLAG.REJECT_UNEXPECTED),
+    )
+    set_tcp_authopt_key(listen_socket, server_key)
+
+    # create client socket:
+    def create_client_socket():
+        with netns_context(nsfixture.client_netns_name):
+            client_socket = socket.socket(address_family, socket.SOCK_STREAM)
+        client_key = tcp_authopt_key(
+            alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+            key="hello",
+        )
+        set_tcp_authopt_key(client_socket, client_key)
+        return client_socket
+
+    # addr match:
+    # with create_client_socket() as client_socket2:
+    #    client_socket2.bind((client_addr2, 0))
+    #    client_socket2.settimeout(1.0)
+    #    client_socket2.connect((server_addr, TCP_SERVER_PORT))
+
+    # addr mismatch:
+    with create_client_socket() as client_socket1:
+        client_socket1.bind((client_addr, 0))
+        with pytest.raises(socket.timeout):
+            client_socket1.settimeout(1.0)
+            client_socket1.connect((server_addr, DEFAULT_TCP_SERVER_PORT))
+
+
+@pytest.mark.parametrize("address_family", [socket.AF_INET, socket.AF_INET6])
+def test_addr_client_bind(exit_stack: ExitStack, address_family):
+    """Client configures different keys with same id but different addresses"""
+    nsfixture = exit_stack.enter_context(NamespaceFixture())
+    server_addr1 = str(nsfixture.get_addr(address_family, 1, 1))
+    server_addr2 = str(nsfixture.get_addr(address_family, 1, 2))
+    client_addr = str(nsfixture.get_addr(address_family, 2, 1))
+
+    # create servers:
+    listen_socket1 = exit_stack.enter_context(
+        create_listen_socket(
+            family=address_family,
+            ns=nsfixture.server_netns_name,
+            bind_addr=server_addr1,
+        )
+    )
+    listen_socket2 = exit_stack.enter_context(
+        create_listen_socket(
+            family=address_family,
+            ns=nsfixture.server_netns_name,
+            bind_addr=server_addr2,
+        )
+    )
+    exit_stack.enter_context(SimpleServerThread(listen_socket1, mode="echo"))
+    exit_stack.enter_context(SimpleServerThread(listen_socket2, mode="echo"))
+
+    # set keys:
+    set_tcp_authopt_key(
+        listen_socket1,
+        tcp_authopt_key(
+            alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+            key="11111",
+        ),
+    )
+    set_tcp_authopt_key(
+        listen_socket2,
+        tcp_authopt_key(
+            alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+            key="22222",
+        ),
+    )
+
+    # create client socket:
+    def create_client_socket():
+        with netns_context(nsfixture.client_netns_name):
+            client_socket = socket.socket(address_family, socket.SOCK_STREAM)
+        set_tcp_authopt_key(
+            client_socket,
+            tcp_authopt_key(
+                alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+                key="11111",
+                flags=TCP_AUTHOPT_KEY_FLAG.BIND_ADDR,
+                addr=server_addr1,
+            ),
+        )
+        set_tcp_authopt_key(
+            client_socket,
+            tcp_authopt_key(
+                alg=TCP_AUTHOPT_ALG.HMAC_SHA_1_96,
+                key="22222",
+                flags=TCP_AUTHOPT_KEY_FLAG.BIND_ADDR,
+                addr=server_addr2,
+            ),
+        )
+        client_socket.settimeout(1.0)
+        client_socket.bind((client_addr, 0))
+        return client_socket
+
+    with create_client_socket() as client_socket1:
+        client_socket1.connect((server_addr1, DEFAULT_TCP_SERVER_PORT))
+        check_socket_echo(client_socket1)
+    with create_client_socket() as client_socket2:
+        client_socket2.connect((server_addr2, DEFAULT_TCP_SERVER_PORT))
+        check_socket_echo(client_socket2)
diff --git a/tools/testing/selftests/tcp_authopt/tcp_authopt_test/utils.py b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/utils.py
new file mode 100644
index 000000000000..473e8e954d92
--- /dev/null
+++ b/tools/testing/selftests/tcp_authopt/tcp_authopt_test/utils.py
@@ -0,0 +1,114 @@
+# SPDX-License-Identifier: GPL-2.0
+import json
+import random
+import socket
+import subprocess
+import typing
+from contextlib import nullcontext
+
+from nsenter import Namespace
+
+# TCP port does not impact Authentication Option so define a single default
+DEFAULT_TCP_SERVER_PORT = 17971
+
+
+def recvall(sock, todo):
+    """Receive exactly todo bytes unless EOF"""
+    data = bytes()
+    while True:
+        chunk = sock.recv(todo)
+        if not len(chunk):
+            return data
+        data += chunk
+        todo -= len(chunk)
+        if todo == 0:
+            return data
+        assert todo > 0
+
+
+def randbytes(count) -> bytes:
+    """Return a random byte array"""
+    return bytes([random.randint(0, 255) for index in range(count)])
+
+
+def check_socket_echo(sock: socket.socket, size=1000):
+    """Send random bytes and check they are received
+
+    The default size is equal to `SimpleServerThread.DEFAULT_BUFSIZE` which
+    means that a single pair of packets will be sent at the TCP level.
+    """
+    send_buf = randbytes(size)
+    sock.sendall(send_buf)
+    recv_buf = recvall(sock, size)
+    assert send_buf == recv_buf
+
+
+def nstat_json(command_prefix: str = "", namespace=None):
+    """Parse nstat output into a python dict"""
+    if namespace is not None:
+        command_prefix += f"ip netns exec {namespace} "
+    runres = subprocess.run(
+        f"{command_prefix}nstat -a --zeros --json",
+        shell=True,
+        check=True,
+        stdout=subprocess.PIPE,
+        encoding="utf-8",
+    )
+    return json.loads(runres.stdout)["kernel"]
+
+
+def netns_context(ns: str = ""):
+    """Create context manager for a certain optional netns
+
+    If the ns argument is empty then just return a `nullcontext`
+    """
+    if ns:
+        return Namespace("/var/run/netns/" + ns, "net")
+    else:
+        return nullcontext()
+
+
+def socket_set_bindtodevice(sock, dev: str):
+    """Set SO_BINDTODEVICE"""
+    opt = dev.encode("utf-8") + b"\0"
+    sock.setsockopt(socket.SOL_SOCKET, socket.SO_BINDTODEVICE, opt)
+
+
+def create_listen_socket(
+    ns: str = "",
+    family=socket.AF_INET,
+    reuseaddr=True,
+    listen_depth=10,
+    bind_addr="",
+    bind_port=DEFAULT_TCP_SERVER_PORT,
+    bind_device: typing.Optional[str] = None,
+):
+    with netns_context(ns):
+        listen_socket = socket.socket(family, socket.SOCK_STREAM)
+    if reuseaddr:
+        listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+    if bind_device:
+        socket_set_bindtodevice(listen_socket, bind_device)
+    listen_socket.bind((str(bind_addr), bind_port))
+    listen_socket.listen(listen_depth)
+    return listen_socket
+
+
+def create_client_socket(
+    ns: str = "", family=socket.AF_INET, bind_addr="", bind_port=0, timeout=1.0
+):
+    with netns_context(ns):
+        client_socket = socket.socket(family, socket.SOCK_STREAM)
+    if bind_addr or bind_port:
+        client_socket.bind((str(bind_addr), bind_port))
+    if timeout is not None:
+        client_socket.settimeout(timeout)
+    return client_socket
+
+
+def socket_set_linger(sock, onoff, value):
+    import struct
+
+    sock.setsockopt(
+        socket.SOL_SOCKET, socket.SO_LINGER, struct.pack("ii", int(onoff), int(value))
+    )
-- 
2.25.1


  parent reply	other threads:[~2021-11-01 16:35 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-01 16:34 [PATCH v2] tcp: Initial support for RFC5925 auth option Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 01/25] tcp: authopt: Initial support and key management Leonard Crestez
2021-11-03  2:29   ` David Ahern
2021-11-05 12:10     ` Leonard Crestez
2021-11-05  1:22   ` Dmitry Safonov
2021-11-05  7:04     ` Leonard Crestez
2021-11-05 14:50       ` Dmitry Safonov
2021-11-05 18:00         ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 02/25] docs: Add user documentation for tcp_authopt Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 03/25] selftests: Initial tcp_authopt test module Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 04/25] selftests: tcp_authopt: Initial sockopt manipulation Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 05/25] tcp: authopt: Add crypto initialization Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 06/25] tcp: authopt: Compute packet signatures Leonard Crestez
2021-11-05  1:53   ` Dmitry Safonov
2021-11-05  6:39     ` Leonard Crestez
2021-11-05  2:08   ` Dmitry Safonov
2021-11-05  6:09     ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 07/25] tcp: Use BIT() for OPTION_* constants Leonard Crestez
2021-11-03  2:31   ` David Ahern
2021-11-03 22:19     ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 08/25] tcp: authopt: Hook into tcp core Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 09/25] tcp: authopt: Disable via sysctl by default Leonard Crestez
2021-11-03  2:39   ` David Ahern
2021-11-05  8:50     ` Leonard Crestez
2021-11-05  1:46   ` Dmitry Safonov
2021-11-01 16:34 ` Leonard Crestez [this message]
2021-11-01 16:34 ` [PATCH v2 11/25] tcp: authopt: Implement Sequence Number Extension Leonard Crestez
2021-11-01 19:22   ` Francesco Ruggeri
2021-11-02 10:03     ` Leonard Crestez
2021-11-02 19:21       ` Francesco Ruggeri
2021-11-03 22:01         ` Leonard Crestez
2021-11-01 20:54   ` Eric Dumazet
2021-11-02  9:50     ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 12/25] tcp: ipv6: Add AO signing for tcp_v6_send_response Leonard Crestez
2021-11-03  2:44   ` David Ahern
2021-11-03 22:09     ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 13/25] tcp: authopt: Add support for signing skb-less replies Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 14/25] tcp: ipv4: Add AO signing for " Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 15/25] selftests: tcp_authopt: Implement SNE in python Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 16/25] selftests: tcp_authopt: Add scapy-based packet signing code Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 17/25] selftests: tcp_authopt: Add packet-level tests Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 18/25] selftests: tcp_authopt: Initial sne test Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 19/25] tcp: authopt: Add key selection controls Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 20/25] selftests: tcp_authopt: Add tests for rollover Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 21/25] tcp: authopt: Add initial l3index support Leonard Crestez
2021-11-03  3:06   ` David Ahern
2021-11-05 12:26     ` Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 22/25] selftests: tcp_authopt: Initial tests for l3mdev handling Leonard Crestez
2021-11-01 16:34 ` [PATCH v2 23/25] selftests: nettest: Rename md5_prefix to key_addr_prefix Leonard Crestez
2021-11-03  3:08   ` David Ahern
2021-11-01 16:34 ` [PATCH v2 24/25] selftests: nettest: Initial tcp_authopt support Leonard Crestez
2021-11-03  3:09   ` David Ahern
2021-11-01 16:35 ` [PATCH v2 25/25] selftests: net/fcnal: " Leonard Crestez
2021-11-03  3:18 ` [PATCH v2] tcp: Initial support for RFC5925 auth option David Ahern
2021-11-03 22:22   ` Leonard Crestez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4b4f69bb41c21af41c9c8b8c9e2d939980d33ec2.1635784253.git.cdleonard@gmail.com \
    --to=cdleonard@gmail.com \
    --cc=0x7f454c46@gmail.com \
    --cc=colona@arista.com \
    --cc=cpaasch@apple.com \
    --cc=davem@davemloft.net \
    --cc=dsahern@kernel.org \
    --cc=edumazet@google.com \
    --cc=fruggeri@arista.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=kuba@kernel.org \
    --cc=kuniyu@amazon.co.jp \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mathew.j.martineau@linux.intel.com \
    --cc=netdev@vger.kernel.org \
    --cc=priyarjha@google.com \
    --cc=shuah@kernel.org \
    --cc=ycheng@google.com \
    --cc=yoshfuji@linux-ipv6.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.