summaryrefslogtreecommitdiffstats
path: root/lib/vrf.c
diff options
context:
space:
mode:
authorIgor Ryzhov <iryzhov@nfware.com>2021-05-07 01:49:40 +0200
committerIgor Ryzhov <iryzhov@nfware.com>2021-05-31 21:12:55 +0200
commit36eef8586d80173a9d64e4b802584014b3780558 (patch)
tree1f423b7d10f02c029f3a31c63510e3d75a9148c2 /lib/vrf.c
parentbgpd: pass correct vrf_id to vrf_socket when creating bgp view socket (diff)
downloadfrr-36eef8586d80173a9d64e4b802584014b3780558.tar.xz
frr-36eef8586d80173a9d64e4b802584014b3780558.zip
lib: fix binding to a vrf
There are two possible use-cases for the `vrf_bind` function: - bind socket to an interface in a vrf - bind socket to a vrf device For the former case, there's one problem - success is returned when the interface is not found. In that case, the socket is left unbound without throwing an error. For the latter case, there are multiple possible problems: - If the name is not set, then the socket is left unbound (zebra, vrrp). - If the name is "default" and there's an interface with that name in the default VRF, then the socket is bound to that interface. - In most daemons, if the router is configured before the VRF is actually created, we're trying to open and bind the socket right after the daemon receives a VRF registration from zebra. We may not receive the VRF-interface registration from zebra yet at that point. Therefore, `if_lookup_by_name` fails, and the socket is left unbound. This commit fixes all the issues and updates the function description. Suggested-by: Pat Ruddy <pat@voltanet.io> Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
Diffstat (limited to 'lib/vrf.c')
-rw-r--r--lib/vrf.c51
1 files changed, 38 insertions, 13 deletions
diff --git a/lib/vrf.c b/lib/vrf.c
index d99ec12ba..185a11664 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;
}