mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 17:12:33 +00:00
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>
This commit is contained in:
parent
e80c797a1f
commit
04a0401f2d
@ -651,6 +651,8 @@ int ospf_if_new_hook(struct interface *ifp)
|
||||
|
||||
ifp->info = XCALLOC(MTYPE_OSPF_IF_INFO, sizeof(struct ospf_if_info));
|
||||
|
||||
IF_OSPF_IF_INFO(ifp)->oii_fd = -1;
|
||||
|
||||
IF_OIFS(ifp) = route_table_init();
|
||||
IF_OIFS_PARAMS(ifp) = route_table_init();
|
||||
|
||||
@ -691,6 +693,8 @@ static int ospf_if_delete_hook(struct interface *ifp)
|
||||
{
|
||||
int rc = 0;
|
||||
struct route_node *rn;
|
||||
struct ospf_if_info *oii;
|
||||
|
||||
rc = ospf_opaque_del_if(ifp);
|
||||
|
||||
/*
|
||||
@ -707,6 +711,13 @@ static int ospf_if_delete_hook(struct interface *ifp)
|
||||
route_table_finish(IF_OIFS(ifp));
|
||||
route_table_finish(IF_OIFS_PARAMS(ifp));
|
||||
|
||||
/* Close per-interface socket */
|
||||
oii = ifp->info;
|
||||
if (oii && oii->oii_fd > 0) {
|
||||
close(oii->oii_fd);
|
||||
oii->oii_fd = -1;
|
||||
}
|
||||
|
||||
XFREE(MTYPE_OSPF_IF_INFO, ifp->info);
|
||||
|
||||
return rc;
|
||||
@ -1367,6 +1378,16 @@ static int ospf_ifp_up(struct interface *ifp)
|
||||
struct ospf_interface *oi;
|
||||
struct route_node *rn;
|
||||
struct ospf_if_info *oii = ifp->info;
|
||||
struct ospf *ospf;
|
||||
|
||||
if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
|
||||
zlog_debug("Zebra: Interface[%s] state change to up.",
|
||||
ifp->name);
|
||||
|
||||
/* Open per-intf write socket if configured */
|
||||
ospf = ifp->vrf->info;
|
||||
if (ospf && ospf->intf_socket_enabled)
|
||||
ospf_ifp_sock_init(ifp);
|
||||
|
||||
ospf_if_recalculate_output_cost(ifp);
|
||||
|
||||
@ -1384,10 +1405,6 @@ static int ospf_ifp_up(struct interface *ifp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE))
|
||||
zlog_debug("Zebra: Interface[%s] state change to up.",
|
||||
ifp->name);
|
||||
|
||||
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
|
||||
if ((oi = rn->info) == NULL)
|
||||
continue;
|
||||
@ -1416,6 +1433,9 @@ static int ospf_ifp_down(struct interface *ifp)
|
||||
ospf_if_down(oi);
|
||||
}
|
||||
|
||||
/* Close per-interface write socket if configured */
|
||||
ospf_ifp_sock_close(ifp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,9 @@ struct ospf_if_info {
|
||||
membership_counts[MEMBER_MAX]; /* multicast group refcnts */
|
||||
|
||||
uint32_t curr_mtu;
|
||||
|
||||
/* Per-interface write socket, configured via 'ospf' object */
|
||||
int oii_fd;
|
||||
};
|
||||
|
||||
struct ospf_interface;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -13,8 +13,11 @@ extern int ospf_if_drop_allspfrouters(struct ospf *, struct prefix *,
|
||||
ifindex_t);
|
||||
extern int ospf_if_add_alldrouters(struct ospf *, struct prefix *, ifindex_t);
|
||||
extern int ospf_if_drop_alldrouters(struct ospf *, struct prefix *, ifindex_t);
|
||||
extern int ospf_if_ipmulticast(struct ospf *, struct prefix *, ifindex_t);
|
||||
extern int ospf_if_ipmulticast(int fd, struct prefix *, ifindex_t);
|
||||
extern int ospf_sock_init(struct ospf *ospf);
|
||||
/* Open, close per-interface write socket */
|
||||
int ospf_ifp_sock_init(struct interface *ifp);
|
||||
int ospf_ifp_sock_close(struct interface *ifp);
|
||||
|
||||
enum ospf_sock_type_e {
|
||||
OSPF_SOCK_NONE = 0,
|
||||
|
@ -618,7 +618,7 @@ static void ospf_write(struct event *thread)
|
||||
struct msghdr msg;
|
||||
struct iovec iov[2];
|
||||
uint8_t type;
|
||||
int ret;
|
||||
int ret, fd;
|
||||
int flags = 0;
|
||||
struct listnode *node;
|
||||
#ifdef WANT_OSPF_WRITE_FRAGMENT
|
||||
@ -633,11 +633,12 @@ static void ospf_write(struct event *thread)
|
||||
struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf;
|
||||
struct in_pktinfo *pi;
|
||||
#endif
|
||||
fd = ospf->fd;
|
||||
|
||||
if (ospf->fd < 0 || ospf->oi_running == 0) {
|
||||
if (fd < 0 || ospf->oi_running == 0) {
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug("%s failed to send, fd %d, instance %u",
|
||||
__func__, ospf->fd, ospf->oi_running);
|
||||
__func__, fd, ospf->oi_running);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -657,6 +658,15 @@ static void ospf_write(struct event *thread)
|
||||
/* convenience - max OSPF data per packet */
|
||||
maxdatasize = oi->ifp->mtu - sizeof(struct ip);
|
||||
#endif /* WANT_OSPF_WRITE_FRAGMENT */
|
||||
|
||||
/* Reset socket fd to use. */
|
||||
fd = ospf->fd;
|
||||
|
||||
/* Check for per-interface socket */
|
||||
if (ospf->intf_socket_enabled &&
|
||||
(IF_OSPF_IF_INFO(oi->ifp))->oii_fd > 0)
|
||||
fd = (IF_OSPF_IF_INFO(oi->ifp))->oii_fd;
|
||||
|
||||
/* Get one packet from queue. */
|
||||
op = ospf_fifo_head(oi->obuf);
|
||||
assert(op);
|
||||
@ -664,8 +674,7 @@ static void ospf_write(struct event *thread)
|
||||
|
||||
if (op->dst.s_addr == htonl(OSPF_ALLSPFROUTERS)
|
||||
|| op->dst.s_addr == htonl(OSPF_ALLDROUTERS))
|
||||
ospf_if_ipmulticast(ospf, oi->address,
|
||||
oi->ifp->ifindex);
|
||||
ospf_if_ipmulticast(fd, oi->address, oi->ifp->ifindex);
|
||||
|
||||
/* Rewrite the md5 signature & update the seq */
|
||||
ospf_make_md5_digest(oi, op);
|
||||
@ -760,13 +769,13 @@ static void ospf_write(struct event *thread)
|
||||
|
||||
#ifdef WANT_OSPF_WRITE_FRAGMENT
|
||||
if (op->length > maxdatasize)
|
||||
ospf_write_frags(ospf->fd, op, &iph, &msg, maxdatasize,
|
||||
ospf_write_frags(fd, op, &iph, &msg, maxdatasize,
|
||||
oi->ifp->mtu, flags, type);
|
||||
#endif /* WANT_OSPF_WRITE_FRAGMENT */
|
||||
|
||||
/* send final fragment (could be first) */
|
||||
sockopt_iphdrincl_swab_htosys(&iph);
|
||||
ret = sendmsg(ospf->fd, &msg, flags);
|
||||
ret = sendmsg(fd, &msg, flags);
|
||||
sockopt_iphdrincl_swab_systoh(&iph);
|
||||
if (IS_DEBUG_OSPF_EVENT)
|
||||
zlog_debug(
|
||||
|
@ -35,12 +35,11 @@
|
||||
#include "ospfd/ospf_spf.h"
|
||||
#include "ospfd/ospf_route.h"
|
||||
#include "ospfd/ospf_zebra.h"
|
||||
/*#include "ospfd/ospf_routemap.h" */
|
||||
#include "ospfd/ospf_vty.h"
|
||||
#include "ospfd/ospf_dump.h"
|
||||
#include "ospfd/ospf_bfd.h"
|
||||
#include "ospfd/ospf_ldp_sync.h"
|
||||
|
||||
#include "ospfd/ospf_network.h"
|
||||
|
||||
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
|
||||
{ .val_bool = true, .match_profile = "datacenter", },
|
||||
@ -12511,6 +12510,9 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf)
|
||||
if (ospf->fr_configured)
|
||||
vty_out(vty, " flood-reduction\n");
|
||||
|
||||
if (!ospf->intf_socket_enabled)
|
||||
vty_out(vty, " no socket-per-interface\n");
|
||||
|
||||
/* Redistribute information print. */
|
||||
config_write_ospf_redistribute(vty, ospf);
|
||||
|
||||
@ -13075,6 +13077,35 @@ DEFPY(ospf_socket_bufsizes,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (per_intf_socket,
|
||||
per_intf_socket_cmd,
|
||||
"[no] socket-per-interface",
|
||||
NO_STR
|
||||
"Use write socket per interface\n")
|
||||
{
|
||||
VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
|
||||
struct listnode *node;
|
||||
struct ospf_interface *oi;
|
||||
|
||||
if (no) {
|
||||
if (ospf->intf_socket_enabled) {
|
||||
ospf->intf_socket_enabled = false;
|
||||
|
||||
/* Iterate and close any sockets */
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
|
||||
ospf_ifp_sock_close(oi->ifp);
|
||||
}
|
||||
} else if (!ospf->intf_socket_enabled) {
|
||||
ospf->intf_socket_enabled = true;
|
||||
|
||||
/* Iterate and open sockets */
|
||||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi))
|
||||
ospf_ifp_sock_init(oi->ifp);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
void ospf_vty_clear_init(void)
|
||||
{
|
||||
install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd);
|
||||
@ -13239,6 +13270,7 @@ void ospf_vty_init(void)
|
||||
install_element(OSPF_NODE, &no_flood_reduction_area_cmd);
|
||||
|
||||
install_element(OSPF_NODE, &ospf_socket_bufsizes_cmd);
|
||||
install_element(OSPF_NODE, &per_intf_socket_cmd);
|
||||
|
||||
/* Init interface related vty commands. */
|
||||
ospf_vty_if_init();
|
||||
|
@ -419,6 +419,7 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name)
|
||||
QOBJ_REG(new, ospf);
|
||||
|
||||
new->fd = -1;
|
||||
new->intf_socket_enabled = true;
|
||||
|
||||
new->recv_sock_bufsize = OSPF_DEFAULT_SOCK_BUFSIZE;
|
||||
new->send_sock_bufsize = OSPF_DEFAULT_SOCK_BUFSIZE;
|
||||
|
@ -431,6 +431,9 @@ struct ospf {
|
||||
uint32_t recv_sock_bufsize;
|
||||
uint32_t send_sock_bufsize;
|
||||
|
||||
/* Per-interface write socket */
|
||||
bool intf_socket_enabled;
|
||||
|
||||
QOBJ_FIELDS;
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(ospf);
|
||||
|
Loading…
Reference in New Issue
Block a user