]> git.proxmox.com Git - mirror_frr.git/commitdiff
ospfd: Bind socket to vrf device
authorChirag Shah <chirag@cumulusnetworks.com>
Wed, 13 Sep 2017 00:27:26 +0000 (17:27 -0700)
committerChirag Shah <chirag@cumulusnetworks.com>
Tue, 3 Oct 2017 16:22:47 +0000 (09:22 -0700)
Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
ospfd/ospf_network.c
ospfd/ospf_network.h
ospfd/ospf_packet.c
ospfd/ospfd.c

index c72c69856c4f4a0ab0a7ac1dc62690a16c5d18a0..f5402e7cd3f2daa0b4b30d8227bdb0c91fd36869 100644 (file)
@@ -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;
 }
index ed5e00315c9a67546423cd7dc56d34ca4193bae8..41a7abda7013ed1af4b6e1d25d7d859c0576b440 100644 (file)
@@ -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 */
index 6ac7bdc2b436054adf9dda2e699dbdc75d57de65..a9a4adf72c3f239c8855308a6c08d0b53ec28f51 100644 (file)
@@ -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,
index d2097e6f5e8d6d27ab333ae331fc7ca44f2c8d6f..ac88ff292d52ad8fedc96f6d173b3e03716279f2 100644 (file)
@@ -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);
                }