xref: /freebsd/tests/sys/netinet/fib_bind.py (revision 948ad32ae1e0811f45e1d38f26636fefed5051f0)
1#
2# Copyright (c) 2026 Stormshield
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6
7import pytest
8import errno
9import os
10import socket
11import struct
12import sys
13import logging
14
15from atf_python.sys.net.vnet import VnetTestTemplate
16from atf_python.sys.net.tools import ToolsHelper
17
18def _common(tunable, addr, domain, type, proto):
19    """
20    Test what happens when we try to bind a socket to an
21    address that is not present in the current FIB.
22    """
23    sysctl_output = ToolsHelper.get_output(f"sysctl {tunable}")
24    tunable_val = int(sysctl_output.split(":")[1])
25    if tunable_val != 0:
26        pytest.skip(f"{tunable} must be set to 0")
27
28    port = 12345 if type != socket.SOCK_RAW else 0
29    s = socket.socket(domain, type, proto)
30    s.setsockopt(socket.SOL_SOCKET, socket.SO_SETFIB, 0)
31
32    failed = False
33    try:
34        s.bind((addr, port))
35    except OSError as e:
36        assert e.errno == errno.EADDRNOTAVAIL
37        failed = True
38    assert failed
39
40    s.setsockopt(socket.SOL_SOCKET, socket.SO_SETFIB, 1)
41
42    failed = False
43    try:
44        s.bind((addr, port))
45    except OSError:
46        failed = True
47    assert not failed
48    s.close()
49
50class TestFibBind(VnetTestTemplate):
51    REQUIRED_MODULES = []
52    TOPOLOGY = {
53        "vnet1": { "ifaces": [ "if1", "if2" ] },
54        "if1": {
55            "prefixes4": [("192.168.1.1/24", "192.168.1.2/24")],
56            "fib": (0, 0),
57        },
58        "if2": {
59            "prefixes4": [("192.168.2.1/24", "192.168.2.2/24")],
60            "fib": (1, 0),
61        },
62    }
63
64    def setup_method(self, method):
65        super().setup_method(method)
66
67    def test_TCP(self):
68        _common("net.inet.tcp.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
69
70    def test_UDP(self):
71        _common("net.inet.udp.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
72
73    def test_RAW(self):
74        _common("net.inet.raw.bind_all_fibs", "192.168.2.1", socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
75
76class TestFibBind6(VnetTestTemplate):
77    REQUIRED_MODULES = []
78    TOPOLOGY = {
79        "vnet1": { "ifaces": [ "if1", "if2" ] },
80        "if1": {
81            "prefixes6": [("2001:db8:0:1::1/64", "2001:db8:0:1::2/64")],
82            "fib": (0, 0),
83        },
84        "if2": {
85            "prefixes6": [("2001:db8:0:2::1/64", "2001:db8:0:2::2/64")],
86            "fib": (1, 0),
87        },
88    }
89
90    def setup_method(self, method):
91        super().setup_method(method)
92
93    def test_TCP(self):
94        _common("net.inet.tcp.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_STREAM, socket.IPPROTO_TCP)
95
96    def test_UDP(self):
97        _common("net.inet.udp.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
98
99    def test_RAW(self):
100        _common("net.inet.raw.bind_all_fibs", "2001:db8:0:2::1", socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_IPV6)
101