diff options
author | Igor Ryzhov <iryzhov@nfware.com> | 2021-05-07 01:49:40 +0200 |
---|---|---|
committer | Igor Ryzhov <iryzhov@nfware.com> | 2021-05-31 21:12:55 +0200 |
commit | 36eef8586d80173a9d64e4b802584014b3780558 (patch) | |
tree | 1f423b7d10f02c029f3a31c63510e3d75a9148c2 /lib/vrf.c | |
parent | bgpd: pass correct vrf_id to vrf_socket when creating bgp view socket (diff) | |
download | frr-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.c | 51 |
1 files changed, 38 insertions, 13 deletions
@@ -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; } |