summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ospfd/ospf_network.c65
-rw-r--r--ospfd/ospf_network.h3
-rw-r--r--ospfd/ospf_packet.c22
-rw-r--r--ospfd/ospfd.c14
4 files changed, 78 insertions, 26 deletions
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index c72c69856..f5402e7cd 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -154,30 +154,51 @@ int ospf_if_ipmulticast(struct ospf *top, struct prefix *p, ifindex_t ifindex)
zlog_warn("can't setsockopt IP_MULTICAST_TTL(1) for fd %d: %s",
top->fd, safe_strerror(errno));
- ret = setsockopt_ipv4_multicast_if(top->fd, p->u.prefix4, ifindex);
- if (ret < 0)
- zlog_warn(
- "can't setsockopt IP_MULTICAST_IF(fd %d, addr %s, "
- "ifindex %u): %s",
- top->fd, inet_ntoa(p->u.prefix4), ifindex,
- safe_strerror(errno));
+ return ret;
+}
+
+int ospf_bind_vrfdevice(struct ospf *ospf, int ospf_sock)
+{
+ int ret = 0;
+#ifdef SO_BINDTODEVICE
+
+ if (ospf && ospf->vrf_id != VRF_DEFAULT &&
+ ospf->vrf_id != VRF_UNKNOWN) {
+ ret = setsockopt(ospf_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ ospf->name,
+ strlen(ospf->name));
+ if (ret < 0) {
+ int save_errno = errno;
+
+ zlog_warn("%s: Could not setsockopt SO_BINDTODEVICE %s",
+ __PRETTY_FUNCTION__,
+ safe_strerror(save_errno));
+ } else {
+ zlog_debug("%s: Bind socket %d to vrf %s id %u device",
+ __PRETTY_FUNCTION__, ospf_sock,
+ ospf->name, ospf->vrf_id);
+ }
+ }
+#endif
return ret;
}
-int ospf_sock_init(void)
+int ospf_sock_init(struct ospf *ospf)
{
int ospf_sock;
int ret, hincl = 1;
int bufsize = (8 * 1024 * 1024);
- if (ospfd_privs.change(ZPRIVS_RAISE))
+ if (ospfd_privs.change(ZPRIVS_RAISE)) {
zlog_err("ospf_sock_init: could not raise privs, %s",
safe_strerror(errno));
+ }
ospf_sock = socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP);
if (ospf_sock < 0) {
int save_errno = errno;
+
if (ospfd_privs.change(ZPRIVS_LOWER))
zlog_err("ospf_sock_init: could not lower privs, %s",
safe_strerror(errno));
@@ -186,17 +207,20 @@ int ospf_sock_init(void)
exit(1);
}
+ ret = ospf_bind_vrfdevice(ospf, ospf_sock);
+ if (ret < 0)
+ goto out;
+
#ifdef IP_HDRINCL
/* we will include IP header with packet */
ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
sizeof(hincl));
if (ret < 0) {
int save_errno = errno;
- if (ospfd_privs.change(ZPRIVS_LOWER))
- zlog_err("ospf_sock_init: could not lower privs, %s",
- safe_strerror(errno));
+
zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
ospf_sock, safe_strerror(save_errno));
+ goto out;
}
#elif defined(IPTOS_PREC_INTERNETCONTROL)
#warning "IP_HDRINCL not available on this system"
@@ -204,13 +228,11 @@ int ospf_sock_init(void)
ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL);
if (ret < 0) {
int save_errno = errno;
- if (ospfd_privs.change(ZPRIVS_LOWER))
- zlog_err("ospf_sock_init: could not lower privs, %s",
- safe_strerror(errno));
+
zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s", tos,
ospf_sock, safe_strerror(save_errno));
close(ospf_sock); /* Prevent sd leak. */
- return ret;
+ goto out;
}
#else /* !IPTOS_PREC_INTERNETCONTROL */
#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
@@ -222,13 +244,14 @@ int ospf_sock_init(void)
if (ret < 0)
zlog_warn("Can't set pktinfo option for fd %d", ospf_sock);
+ setsockopt_so_sendbuf(ospf_sock, bufsize);
+ setsockopt_so_recvbuf(ospf_sock, bufsize);
+
+ ospf->fd = ospf_sock;
+out:
if (ospfd_privs.change(ZPRIVS_LOWER)) {
zlog_err("ospf_sock_init: could not lower privs, %s",
safe_strerror(errno));
}
-
- setsockopt_so_sendbuf(ospf_sock, bufsize);
- setsockopt_so_recvbuf(ospf_sock, bufsize);
-
- return ospf_sock;
+ return ret;
}
diff --git a/ospfd/ospf_network.h b/ospfd/ospf_network.h
index ed5e00315..41a7abda7 100644
--- a/ospfd/ospf_network.h
+++ b/ospfd/ospf_network.h
@@ -29,6 +29,7 @@ extern int ospf_if_drop_allspfrouters(struct ospf *, struct prefix *,
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_sock_init(void);
+extern int ospf_sock_init(struct ospf *ospf);
+extern int ospf_bind_vrfdevice(struct ospf *, int);
#endif /* _ZEBRA_OSPF_NETWORK_H */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 6ac7bdc2b..a9a4adf72 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -648,6 +648,9 @@ static int ospf_write(struct thread *thread)
/* clang-format off */
#define OSPF_WRITE_IPHL_SHIFT 2
int pkt_count = 0;
+ unsigned char cmsgbuf[64] = {};
+ struct cmsghdr *cm = (struct cmsghdr *)cmsgbuf;
+ struct in_pktinfo *pi;
ospf->t_write = NULL;
@@ -753,14 +756,27 @@ static int ospf_write(struct thread *thread)
msg.msg_namelen = sizeof(sa_dst);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
+ msg.msg_control = (caddr_t)cm;
+
iov[0].iov_base = (char *)&iph;
iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT;
iov[1].iov_base = STREAM_PNT(op->s);
iov[1].iov_len = op->length;
-/* Sadly we can not rely on kernels to fragment packets because of either
- * IP_HDRINCL and/or multicast destination being set.
- */
+ cm->cmsg_level = SOL_IP;
+ cm->cmsg_type = IP_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+ pi = (struct in_pktinfo *)CMSG_DATA(cm);
+ pi->ipi_ifindex = oi->ifp->ifindex;
+
+ msg.msg_controllen = cm->cmsg_len;
+
+
+ /* Sadly we can not rely on kernels to fragment packets
+ * because of either IP_HDRINCL and/or multicast
+ * destination being set.
+ */
+
#ifdef WANT_OSPF_WRITE_FRAGMENT
if (op->length > maxdatasize)
ospf_write_frags(ospf->fd, op, &iph, &msg, maxdatasize,
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index d2097e6f5..ac88ff292 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -67,6 +67,7 @@ struct ospf_master *om;
extern struct zclient *zclient;
extern struct in_addr router_id_zebra;
+extern struct zebra_privs_t ospfd_privs;
static void ospf_remove_vls_through_area(struct ospf *, struct ospf_area *);
@@ -308,7 +309,7 @@ static struct ospf *ospf_new(u_short instance, const char *name)
new->lsa_refresh_interval, &new->t_lsa_refresher);
new->lsa_refresher_started = monotime(NULL);
- if ((new->fd = ospf_sock_init()) < 0) {
+ if ((ospf_sock_init(new)) < 0) {
zlog_err(
"ospf_new: fatal error: ospf_sock_init was unable to open "
"a socket");
@@ -2013,6 +2014,17 @@ static int ospf_vrf_enable(struct vrf *vrf)
old_vrf_id);
if (old_vrf_id != ospf->vrf_id) {
+ if (ospfd_privs.change(ZPRIVS_RAISE)) {
+ zlog_err("ospf_sock_init: could not raise privs, %s",
+ safe_strerror(errno));
+ }
+ if (ospf_bind_vrfdevice(ospf, ospf->fd) < 0)
+ return 0;
+ if (ospfd_privs.change(ZPRIVS_LOWER)) {
+ zlog_err("ospf_sock_init: could not lower privs, %s",
+ safe_strerror(errno));
+ }
+
ospf->oi_running = 1;
ospf_router_id_update(ospf);
}