/* VRF is default VRF. silently ignore */
if (!vrf || vrf->vrf_id == VRF_DEFAULT)
- return 0;
+ return 1; /* 1 = default */
/* VRF has no NETNS backend. silently ignore */
if (vrf->data.l.netns_name[0] == '\0')
- return 0;
+ return 2; /* 2 = no netns */
name = ns_netns_pathname(NULL, vrf->data.l.netns_name);
if (debug_vrf)
zlog_debug("VRF_SWITCH: %s(%u)", name, vrf->vrf_id);
}
}
+static int vrf_default_accepts_vrf(int type)
+{
+ const char *fname = NULL;
+ char buf[32] = {0x0};
+ int ret = 0;
+ FILE *fd = NULL;
+
+ /*
+ * TCP & UDP services running in the default VRF context (ie., not bound
+ * to any VRF device) can work across all VRF domains by enabling the
+ * tcp_l3mdev_accept and udp_l3mdev_accept sysctl options:
+ * sysctl -w net.ipv4.tcp_l3mdev_accept=1
+ * sysctl -w net.ipv4.udp_l3mdev_accept=1
+ */
+ if (type == SOCK_STREAM)
+ fname = "/proc/sys/net/ipv4/tcp_l3mdev_accept";
+ else if (type == SOCK_DGRAM)
+ fname = "/proc/sys/net/ipv4/udp_l3mdev_accept";
+ else
+ return ret;
+ fd = fopen(fname, "r");
+ if (fd == NULL)
+ return ret;
+ fgets(buf, 32, fd);
+ ret = atoi(buf);
+ fclose(fd);
+ return ret;
+}
+
/* Create a socket for the VRF. */
int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
char *interfacename)
if (ret < 0)
zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
safe_strerror(errno));
+ if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
+ zlog_err("VRF socket not used since net.ipv4.%s_l3mdev_accept != 0",
+ (type == SOCK_STREAM ? "tcp" : "udp"));
+ errno = EEXIST; /* not sure if this is the best error... */
+ return -2;
+ }
ret = socket(domain, type, protocol);
save_errno = errno;
ret2 = vrf_switchback_to_initial();