summaryrefslogtreecommitdiff
path: root/ospfd/ospf_network.c
diff options
context:
space:
mode:
authorMark Stapp <mjs@labn.net>2023-03-29 16:58:25 -0400
committerMark Stapp <mjs@labn.net>2023-04-11 10:16:07 -0400
commit04a0401f2de44feaadb8f90aae0f53f55580415e (patch)
tree2977bbd8a315abd0b5389735360d2f80fbf68503 /ospfd/ospf_network.c
parente80c797a1f8f98c129a9605a174d451356dde008 (diff)
ospfd: support write socket per interface
Add support for a write socket per interface, enabled by default at the ospf instance level. An ospf instance-level config allows this to be disabled, reverting to the older behavior where a single per-instance socket is used for sending and receiving packets. Signed-off-by: Mark Stapp <mjs@labn.net>
Diffstat (limited to 'ospfd/ospf_network.c')
-rw-r--r--ospfd/ospf_network.c114
1 files changed, 94 insertions, 20 deletions
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index bd5cd7682a..aff8ed05c7 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -15,6 +15,7 @@
#include "sockopt.h"
#include "privs.h"
#include "lib_errors.h"
+#include "lib/table.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -119,61 +120,60 @@ int ospf_if_drop_alldrouters(struct ospf *top, struct prefix *p,
return ret;
}
-int ospf_if_ipmulticast(struct ospf *top, struct prefix *p, ifindex_t ifindex)
+int ospf_if_ipmulticast(int fd, struct prefix *p, ifindex_t ifindex)
{
uint8_t val;
int ret, len;
/* Prevent receiving self-origined multicast packets. */
- ret = setsockopt_ipv4_multicast_loop(top->fd, 0);
+ ret = setsockopt_ipv4_multicast_loop(fd, 0);
if (ret < 0)
flog_err(EC_LIB_SOCKET,
"can't setsockopt IP_MULTICAST_LOOP(0) for fd %d: %s",
- top->fd, safe_strerror(errno));
+ fd, safe_strerror(errno));
/* Explicitly set multicast ttl to 1 -- endo. */
val = 1;
len = sizeof(val);
- ret = setsockopt(top->fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val,
- len);
+ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (void *)&val, len);
if (ret < 0)
flog_err(EC_LIB_SOCKET,
"can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
- top->fd, safe_strerror(errno));
+ fd, safe_strerror(errno));
#ifndef GNU_LINUX
/* For GNU LINUX ospf_write uses IP_PKTINFO, in_pktinfo to send
* packet out of ifindex. Below would be used Non Linux system.
*/
- ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
+ ret = setsockopt_ipv4_multicast_if(fd, p->u.prefix4, ifindex);
if (ret < 0)
flog_err(EC_LIB_SOCKET,
"can't setsockopt IP_MULTICAST_IF(fd %d, addr %pI4, ifindex %u): %s",
- top->fd, &p->u.prefix4, ifindex,
+ fd, &p->u.prefix4, ifindex,
safe_strerror(errno));
#endif
return ret;
}
-int ospf_sock_init(struct ospf *ospf)
+/*
+ * Helper to open and set up a socket; returns the new fd on success,
+ * -1 on error.
+ */
+static int sock_init_common(vrf_id_t vrf_id, const char *name, int *pfd)
{
int ospf_sock;
int ret, hincl = 1;
- /* silently ignore. already done */
- if (ospf->fd > 0)
- return -1;
-
- if (ospf->vrf_id == VRF_UNKNOWN) {
+ if (vrf_id == VRF_UNKNOWN) {
/* silently return since VRF is not ready */
return -1;
}
+
frr_with_privs(&ospfd_privs) {
ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
- ospf->vrf_id, ospf->name);
+ vrf_id, name);
if (ospf_sock < 0) {
- flog_err(EC_LIB_SOCKET,
- "ospf_read_sock_init: socket: %s",
+ flog_err(EC_LIB_SOCKET, "%s: socket: %s", __func__,
safe_strerror(errno));
return -1;
}
@@ -212,10 +212,8 @@ int ospf_sock_init(struct ospf *ospf)
ospf_sock);
}
- /* Update socket buffer sizes */
- ospf_sock_bufsize_update(ospf, ospf_sock, OSPF_SOCK_BOTH);
+ *pfd = ospf_sock;
- ospf->fd = ospf_sock;
return ret;
}
@@ -237,3 +235,79 @@ void ospf_sock_bufsize_update(const struct ospf *ospf, int sock,
setsockopt_so_sendbuf(sock, bufsize);
}
}
+
+int ospf_sock_init(struct ospf *ospf)
+{
+ int ret;
+
+ /* silently ignore. already done */
+ if (ospf->fd > 0)
+ return -1;
+
+ ret = sock_init_common(ospf->vrf_id, ospf->name, &(ospf->fd));
+
+ if (ret >= 0) /* Update socket buffer sizes */
+ ospf_sock_bufsize_update(ospf, ospf->fd, OSPF_SOCK_BOTH);
+
+ return ret;
+}
+
+/*
+ * Open per-interface write socket
+ */
+int ospf_ifp_sock_init(struct interface *ifp)
+{
+ struct ospf_if_info *oii;
+ struct ospf_interface *oi;
+ struct ospf *ospf;
+ struct route_node *rn;
+ int ret;
+
+ oii = IF_OSPF_IF_INFO(ifp);
+ if (oii == NULL)
+ return -1;
+
+ if (oii->oii_fd > 0)
+ return 0;
+
+ rn = route_top(IF_OIFS(ifp));
+ if (rn && rn->info) {
+ oi = rn->info;
+ ospf = oi->ospf;
+ } else
+ return -1;
+
+ ret = sock_init_common(ifp->vrf->vrf_id, ifp->name, &oii->oii_fd);
+
+ if (ret >= 0) /* Update socket buffer sizes */
+ ospf_sock_bufsize_update(ospf, oii->oii_fd, OSPF_SOCK_BOTH);
+
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("%s: ifp %s, oii %p, fd %d", __func__, ifp->name,
+ oii, oii->oii_fd);
+
+ return ret;
+}
+
+/*
+ * Close per-interface write socket
+ */
+int ospf_ifp_sock_close(struct interface *ifp)
+{
+ struct ospf_if_info *oii;
+
+ oii = IF_OSPF_IF_INFO(ifp);
+ if (oii == NULL)
+ return 0;
+
+ if (oii->oii_fd > 0) {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug("%s: ifp %s, oii %p, fd %d", __func__,
+ ifp->name, oii, oii->oii_fd);
+
+ close(oii->oii_fd);
+ oii->oii_fd = -1;
+ }
+
+ return 0;
+}