]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: move IP_PKTINFO on send on a dedicated function
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 19 Feb 2024 14:21:13 +0000 (15:21 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 20 Feb 2024 15:42:05 +0000 (16:42 +0100)
When using listener socket, source address for emission is explicitely
set using ancillary data for sendmsg(). This is useful to guarantee the
correct address is used when binding on a non-explicit address.

This code was implemented directly under qc_snd_buf(). However, it is
quite complex due to portability issue. For IPv4, two parallel
implementations coexist, defined under IP_PKTINFO or IP_RECVDSTADDR. For
IPv6, another option is defined under IPV6_RECVPKTINFO. Each variant
uses its distinct name which increase the code complexity.

Extract ancillary data filling in a dedicated function named
cmsg_set_saddr(). This reduces greatly the body of qc_snd_buf(). Such
functions can be replicated when other ancillary data type will be
implemented. This will notably be useful for GSO implementation.

src/quic_sock.c

index 47534beb3236c3ce337c114bd95b702e1d96de7e..14db339f5b0968c2073549d6c74fa13c94a09ef4 100644 (file)
@@ -566,6 +566,86 @@ void quic_conn_sock_fd_iocb(int fd)
        TRACE_LEAVE(QUIC_EV_CONN_RCV, qc);
 }
 
+static void cmsg_set_saddr(struct msghdr *msg, struct cmsghdr **cmsg,
+                           struct sockaddr_storage *saddr)
+{
+       struct cmsghdr *c;
+#ifdef IP_PKTINFO
+       struct in_pktinfo *in;
+#endif /* IP_PKTINFO */
+#ifdef IPV6_RECVPKTINFO
+       struct in6_pktinfo *in6;
+#endif /* IPV6_RECVPKTINFO */
+       size_t sz = 0;
+
+       /* First determine size of ancillary data depending on the system support. */
+       switch (saddr->ss_family) {
+       case AF_INET:
+#if defined(IP_PKTINFO)
+               sz = sizeof(struct in_pktinfo);
+#elif defined(IP_RECVDSTADDR)
+               sz = sizeof(struct in_addr);
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+               break;
+       case AF_INET6:
+#ifdef IPV6_RECVPKTINFO
+               sz = sizeof(struct in6_pktinfo);
+#endif /* IPV6_RECVPKTINFO */
+               break;
+       default:
+               break;
+       }
+
+       /* Size is null if system does not support send source address setting. */
+       if (!sz)
+               return;
+
+       /* Set first msg_controllen to be able to use CMSG_* macros. */
+       msg->msg_controllen += CMSG_SPACE(sz);
+
+       *cmsg = !(*cmsg) ? CMSG_FIRSTHDR(msg) : CMSG_NXTHDR(msg, *cmsg);
+       ALREADY_CHECKED(*cmsg);
+       c = *cmsg;
+       c->cmsg_len = CMSG_LEN(sz);
+
+       switch (saddr->ss_family) {
+       case AF_INET:
+               c->cmsg_level = IPPROTO_IP;
+#if defined(IP_PKTINFO)
+               c->cmsg_type = IP_PKTINFO;
+               in = (struct in_pktinfo *)CMSG_DATA(c);
+               in->ipi_ifindex = 0;
+               in->ipi_addr.s_addr = 0;
+               memcpy(&in->ipi_spec_dst,
+                      &((struct sockaddr_in *)saddr)->sin_addr,
+                      sizeof(struct in_addr));
+#elif defined(IP_RECVDSTADDR)
+               c->cmsg_type = IP_SENDSRCADDR;
+               memcpy(CMSG_DATA(c),
+                      &((struct sockaddr_in *)saddr)->sin_addr,
+                      sizeof(struct in_addr));
+#endif /* IP_PKTINFO || IP_RECVDSTADDR */
+
+               break;
+
+       case AF_INET6:
+#ifdef IPV6_RECVPKTINFO
+               c->cmsg_level = IPPROTO_IPV6;
+               c->cmsg_type = IPV6_PKTINFO;
+               in6 = (struct in6_pktinfo *)CMSG_DATA(c);
+               in6->ipi6_ifindex = 0;
+               memcpy(&in6->ipi6_addr,
+                      &((struct sockaddr_in6 *)saddr)->sin6_addr,
+                      sizeof(struct in6_addr));
+#endif /* IPV6_RECVPKTINFO */
+
+               break;
+
+       default:
+               break;
+       }
+}
+
 /* Send a datagram stored into <buf> buffer with <sz> as size.
  * The caller must ensure there is at least <sz> bytes in this buffer.
  *
@@ -594,13 +674,7 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
                else if (is_addr(&qc->local_addr)) {
                        struct msghdr msg;
                        struct iovec vec;
-                       struct cmsghdr *cmsg;
-#ifdef IP_PKTINFO
-                       struct in_pktinfo *in;
-#endif /* IP_PKTINFO */
-#ifdef IPV6_RECVPKTINFO
-                       struct in6_pktinfo *in6;
-#endif /* IPV6_RECVPKTINFO */
+                       struct cmsghdr *cmsg = NULL;
                        union {
 #ifdef IP_PKTINFO
                                char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
@@ -619,58 +693,8 @@ int qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t sz,
                        msg.msg_iov = &vec;
                        msg.msg_iovlen = 1;
 
-                       switch (qc->local_addr.ss_family) {
-                       case AF_INET:
-#if defined(IP_PKTINFO)
-                               msg.msg_control = u.buf;
-                               msg.msg_controllen = sizeof(u.buf);
-
-                               cmsg = CMSG_FIRSTHDR(&msg);
-                               in = (struct in_pktinfo *)CMSG_DATA(cmsg);
-                               in->ipi_ifindex = 0;
-                               in->ipi_addr.s_addr = 0;
-                               memcpy(&in->ipi_spec_dst,
-                                      &((struct sockaddr_in *)&qc->local_addr)->sin_addr,
-                                      sizeof(struct in_addr));
-
-                               cmsg->cmsg_level = IPPROTO_IP;
-                               cmsg->cmsg_type = IP_PKTINFO;
-                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
-#elif defined(IP_RECVDSTADDR)
-                               msg.msg_control = u.bufaddr;
-                               msg.msg_controllen = sizeof(u.bufaddr);
-
-                               cmsg = CMSG_FIRSTHDR(&msg);
-                               cmsg->cmsg_level = IPPROTO_IP;
-                               cmsg->cmsg_type = IP_SENDSRCADDR;
-                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
-                               memcpy(CMSG_DATA(cmsg),
-                                      &((struct sockaddr_in *)&qc->local_addr)->sin_addr,
-                                      sizeof(struct in_addr));
-#endif /* IP_PKTINFO || IP_RECVDSTADDR */
-                               break;
-
-                       case AF_INET6:
-#ifdef IPV6_RECVPKTINFO
-                               msg.msg_control = u.buf6;
-                               msg.msg_controllen = sizeof(u.buf6);
-
-                               cmsg = CMSG_FIRSTHDR(&msg);
-                               in6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
-                               in6->ipi6_ifindex = 0;
-                               memcpy(&in6->ipi6_addr,
-                                      &((struct sockaddr_in6 *)&qc->local_addr)->sin6_addr,
-                                      sizeof(struct in6_addr));
-
-                               cmsg->cmsg_level = IPPROTO_IPV6;
-                               cmsg->cmsg_type = IPV6_PKTINFO;
-                               cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
-#endif /* IPV6_RECVPKTINFO */
-                               break;
-
-                       default:
-                               break;
-                       }
+                       msg.msg_control = u.bufaddr;
+                       cmsg_set_saddr(&msg, &cmsg, &qc->local_addr);
 
                        ret = sendmsg(qc->li->rx.fd, &msg,
                                      MSG_DONTWAIT|MSG_NOSIGNAL);