summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_network.c5
-rw-r--r--doc/user/Useful_Sysctl_Settings.md3
-rw-r--r--doc/user/installation.rst23
-rw-r--r--doc/user/zebra.rst4
-rw-r--r--lib/vrf.c51
-rw-r--r--lib/vrf.h11
-rw-r--r--tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py7
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py20
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py11
-rw-r--r--tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py8
-rw-r--r--tests/topotests/lib/common_config.py48
-rwxr-xr-xtests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py13
13 files changed, 72 insertions, 134 deletions
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 860c5fd382..137f0a6b59 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -895,7 +895,10 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
frr_with_privs(&bgpd_privs) {
sock = vrf_socket(ainfo->ai_family,
ainfo->ai_socktype,
- ainfo->ai_protocol, bgp->vrf_id,
+ ainfo->ai_protocol,
+ (bgp->inst_type
+ != BGP_INSTANCE_TYPE_VIEW
+ ? bgp->vrf_id : VRF_DEFAULT),
(bgp->inst_type
== BGP_INSTANCE_TYPE_VRF
? bgp->name : NULL));
diff --git a/doc/user/Useful_Sysctl_Settings.md b/doc/user/Useful_Sysctl_Settings.md
index eaf97b969c..0ebf9119b2 100644
--- a/doc/user/Useful_Sysctl_Settings.md
+++ b/doc/user/Useful_Sysctl_Settings.md
@@ -56,7 +56,4 @@ net.ipv6.neigh.default.base_reachable_time_ms=14400000
# Use neigh information on selection of nexthop for multipath hops
net.ipv4.fib_multipath_use_neigh=1
-
-# Allows Apps to Work with VRF
-net.ipv4.tcp_l3mdev_accept=1
```
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index dbd95aca40..f7e45a6231 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -541,20 +541,15 @@ Additional kernel modules are also needed to support MPLS forwarding.
:makevar:`VRF forwarding`
General information on Linux VRF support can be found in
- https://www.kernel.org/doc/Documentation/networking/vrf.txt. Kernel
- support for VRFs was introduced in 4.3 and improved upon through
- 4.13, which is the version most used in FRR testing (as of June
- 2018). Additional background on using Linux VRFs and kernel specific
- features can be found in
- http://schd.ws/hosted_files/ossna2017/fe/vrf-tutorial-oss.pdf.
-
- A separate BGP TCP socket is opened per VRF.
-
- **Important note** as of June 2018, Kernel versions 4.14-4.18 have a
- known bug where VRF-specific TCP sockets are not properly handled. When
- running these kernel versions, if unable to establish any VRF BGP
- adjacencies, downgrade to 4.13. The issue was fixed in 4.14.57, 4.17.9
- and more recent kernel versions.
+ https://www.kernel.org/doc/Documentation/networking/vrf.txt.
+
+ Kernel support for VRFs was introduced in 4.3, but there are known issues
+ in versions up to 4.15 (for IPv4) and 5.0 (for IPv6). The FRR CI system
+ doesn't perform VRF tests on older kernel versions, and VRFs may not work
+ on them. If you experience issues with VRF support, you should upgrade your
+ kernel version.
+
+ .. seealso:: :ref:`zebra-vrf`
Building
^^^^^^^^
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 1539f9a9d1..ae2235820c 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -261,8 +261,6 @@ Link Parameters Commands
Allows nexthop tracking to resolve via the default route. This is useful
when e.g. you want to allow BGP to peer across the default route.
-.. _zebra-vrf:
-
Administrative Distance
=======================
@@ -338,6 +336,8 @@ work FRR must use the same metric when issuing the replace command.
Currently FRR only supports Route Replace semantics using the Linux
Kernel.
+.. _zebra-vrf:
+
Virtual Routing and Forwarding
==============================
diff --git a/lib/vrf.c b/lib/vrf.c
index d99ec12ba8..185a11664a 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -994,25 +994,50 @@ const char *vrf_get_default_name(void)
return vrf_default_name;
}
-int vrf_bind(vrf_id_t vrf_id, int fd, const char *name)
+int vrf_bind(vrf_id_t vrf_id, int fd, const char *ifname)
{
int ret = 0;
struct interface *ifp;
+ struct vrf *vrf;
+
+ if (fd < 0)
+ return -1;
+
+ if (vrf_id == VRF_UNKNOWN)
+ return -1;
+
+ /* can't bind to a VRF that doesn't exist */
+ vrf = vrf_lookup_by_id(vrf_id);
+ if (!vrf_is_enabled(vrf))
+ return -1;
+
+ if (ifname && strcmp(ifname, vrf->name)) {
+ /* binding to a regular interface */
+
+ /* can't bind to an interface that doesn't exist */
+ ifp = if_lookup_by_name(ifname, vrf_id);
+ if (!ifp)
+ return -1;
+ } else {
+ /* binding to a VRF device */
+
+ /* nothing to do for netns */
+ if (vrf_is_backend_netns())
+ return 0;
+
+ /* nothing to do for default vrf */
+ if (vrf_id == VRF_DEFAULT)
+ return 0;
+
+ ifname = vrf->name;
+ }
- if (fd < 0 || name == NULL)
- return fd;
- /* the device should exist
- * otherwise we should return
- * case ifname = vrf in netns mode => return
- */
- ifp = if_lookup_by_name(name, vrf_id);
- if (!ifp)
- return fd;
#ifdef SO_BINDTODEVICE
- ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name)+1);
+ ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
+ strlen(ifname) + 1);
if (ret < 0)
- zlog_debug("bind to interface %s failed, errno=%d", name,
- errno);
+ zlog_err("bind to interface %s failed, errno=%d", ifname,
+ errno);
#endif /* SO_BINDTODEVICE */
return ret;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index c79dd99b9a..7ce03079dd 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -251,15 +251,14 @@ extern int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
const char *name);
/*
- * Binds a socket to a VRF device.
+ * Binds a socket to an interface (ifname) in a VRF (vrf_id).
*
- * If name is null, the socket is not bound, irrespective of any other
- * arguments.
+ * If ifname is NULL or is equal to the VRF name then bind to a VRF device.
+ * Otherwise, bind to the specified interface in the specified VRF.
*
- * name should be the name of the VRF device. vrf_id should be the
- * corresponding vrf_id (the ifindex of the device).
+ * Returns 0 on success and -1 on failure.
*/
-extern int vrf_bind(vrf_id_t vrf_id, int fd, const char *name);
+extern int vrf_bind(vrf_id_t vrf_id, int fd, const char *ifname);
/* VRF ioctl operations */
extern int vrf_getaddrinfo(const char *node, const char *service,
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
index 320e6d430c..36605d44f0 100644
--- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -42,7 +42,6 @@ sys.path.append(os.path.join(CWD, "../"))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
-from lib.common_config import adjust_router_l3mdev
# Required to instantiate the topology builder class.
from mininet.topo import Topo
@@ -130,7 +129,6 @@ def setup_module(mod):
logger.info("result: " + output)
router = tgen.gears["r2"]
- adjust_router_l3mdev(tgen, "r2")
for cmd in cmds_vrflite:
logger.info("cmd to r2: " + cmd.format("r2"))
output = router.run(cmd.format("r2"))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 5d97537bd0..c2f85c68c4 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -84,7 +84,6 @@ from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from lib.ltemplate import ltemplateRtrCmd
-from lib.common_config import adjust_router_l3mdev
# Required to instantiate the topology builder class.
from mininet.topo import Topo
@@ -176,9 +175,6 @@ def ltemplatePreRouterStartHook():
"ip link set dev {0}-cust1 up",
]
for rtr in rtrs:
- # adjust handling of VRF traffic
- adjust_router_l3mdev(tgen, rtr)
-
for cmd in cmds:
cc.doCmd(tgen, rtr, cmd.format(rtr))
cc.doCmd(tgen, rtr, "ip link set dev {0}-eth4 master {0}-cust1".format(rtr))
@@ -219,9 +215,6 @@ def ltemplatePreRouterStartHook():
"ip link set dev {0}-cust2 up",
]
for rtr in rtrs:
- # adjust handling of VRF traffic
- adjust_router_l3mdev(tgen, rtr)
-
for cmd in cmds:
cc.doCmd(tgen, rtr, cmd.format(rtr))
cc.doCmd(tgen, rtr, "ip link set dev {0}-eth0 master {0}-cust2".format(rtr))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
index f7b9bad5fa..75158b127e 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_vrf.py
@@ -1,24 +1,4 @@
from lib.lutil import luCommand
-from lib.common_config import kernel_requires_l3mdev_adjustment
-
-l3mdev_accept = kernel_requires_l3mdev_adjustment()
-l3mdev_rtrs = ["r1", "r3", "r4", "ce4"]
-for rtr in l3mdev_rtrs:
- luCommand(rtr, "sysctl net.ipv4.tcp_l3mdev_accept", " = \d*", "none", "")
- found = luLast()
- luCommand(
- rtr, "ss -naep", ":179", "pass", "IPv4:bgp, l3mdev{}".format(found.group(0))
- )
- luCommand(rtr, "ss -naep", ":.*:179", "pass", "IPv6:bgp")
- luCommand(
- rtr,
- "sysctl net.ipv4.tcp_l3mdev_accept",
- " = {}".format(l3mdev_accept),
- "pass",
- "l3mdev matches expected (real/expected{}/{})".format(
- found.group(0), l3mdev_accept
- ),
- )
rtrs = ["r1", "r3", "r4"]
for rtr in rtrs:
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
index 92ee8513e1..a17819f747 100644
--- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
@@ -42,7 +42,7 @@ sys.path.append(os.path.join(CWD, "../"))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
-from lib.common_config import adjust_router_l3mdev
+from lib.common_config import required_linux_kernel_version
# Required to instantiate the topology builder class.
from mininet.topo import Topo
@@ -66,6 +66,12 @@ class BGPIPV6RTADVVRFTopo(Topo):
def setup_module(mod):
"Sets up the pytest environment"
+
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("5.0")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
tgen = Topogen(BGPIPV6RTADVVRFTopo, mod.__name__)
tgen.start_topology()
@@ -84,9 +90,6 @@ def setup_module(mod):
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
- # adjust handling of vrf traffic
- adjust_router_l3mdev(tgen, rname)
-
for rname, router in router_list.items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
index b7fe0c2ddb..ff1544e4a2 100644
--- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py
@@ -41,10 +41,7 @@ from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import (
- required_linux_kernel_version,
- adjust_router_l3mdev,
-)
+from lib.common_config import required_linux_kernel_version
from mininet.topo import Topo
@@ -124,9 +121,6 @@ def setup_module(mod):
for cmd in cmds:
output = tgen.net[rname].cmd(cmd.format(rname))
- # adjust handling of vrf traffic
- adjust_router_l3mdev(tgen, rname)
-
for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 5a904423c2..ee7cd6a7af 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -4487,51 +4487,3 @@ def verify_ip_nht(tgen, input_dict):
logger.debug("Exiting lib API: verify_ip_nht()")
return False
-
-
-def kernel_requires_l3mdev_adjustment():
- """
- Checks if the L3 master device needs to be adjusted to handle VRF traffic
- based on kernel version.
-
- Returns
- -------
- 1 or 0
- """
-
- if version_cmp(platform.release(), "4.15") >= 0:
- return 1
- return 0
-
-
-def adjust_router_l3mdev(tgen, router):
- """
- Adjusts a routers L3 master device to handle VRF traffic depending on kernel
- version.
-
- Parameters
- ----------
- * `tgen` : tgen object
- * `router` : router id to be configured.
-
- Returns
- -------
- True
- """
-
- l3mdev_accept = kernel_requires_l3mdev_adjustment()
-
- logger.info(
- "router {0}: setting net.ipv4.tcp_l3mdev_accept={1}".format(
- router, l3mdev_accept
- )
- )
-
- output = tgen.net[router].cmd("sysctl -n net.ipv4.tcp_l3mdev_accept")
- logger.info("router {0}: existing tcp_l3mdev_accept was {1}".format(router, output))
-
- tgen.net[router].cmd(
- "sysctl -w net.ipv4.tcp_l3mdev_accept={}".format(l3mdev_accept)
- )
-
- return True
diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
index fa2784ee7e..e1857abc4f 100755
--- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
+++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py
@@ -92,10 +92,7 @@ from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from lib.topotest import iproute2_is_vrf_capable
-from lib.common_config import (
- required_linux_kernel_version,
- adjust_router_l3mdev,
-)
+from lib.common_config import required_linux_kernel_version
#####################################################
##
@@ -159,6 +156,11 @@ class NetworkTopo(Topo):
def setup_module(mod):
"Sets up the pytest environment"
+ # Required linux kernel version for this suite to run.
+ result = required_linux_kernel_version("5.0")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
tgen = Topogen(NetworkTopo, mod.__name__)
tgen.start_topology()
@@ -197,9 +199,6 @@ def setup_module(mod):
for cmd in cmds2:
output = tgen.net[rname].cmd(cmd.format(rname))
- # adjust handling of vrf traffic
- adjust_router_l3mdev(tgen, rname)
-
for rname, router in tgen.routers().items():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))