git: 8268d82cff1b - main - Remove per-packet ifa refcounting from IPv6 fast path.

Alexander V. Chernikov melifaro at FreeBSD.org
Mon Feb 15 22:33:31 UTC 2021


The branch main has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=8268d82cff1bcd7969e5b3c676f28684784a7a43

commit 8268d82cff1bcd7969e5b3c676f28684784a7a43
Author:     Alexander V. Chernikov <melifaro at FreeBSD.org>
AuthorDate: 2021-02-15 21:59:21 +0000
Commit:     Alexander V. Chernikov <melifaro at FreeBSD.org>
CommitDate: 2021-02-15 22:33:12 +0000

    Remove per-packet ifa refcounting from IPv6 fast path.
    
    Currently ip6_input() calls in6ifa_ifwithaddr() for
     every local packet, in order to check if the target ip
     belongs to the local ifa in proper state and increase
     its counters.
    
    in6ifa_ifwithaddr() references found ifa.
    With epoch changes, both `ip6_input()` and all other current callers
     of `in6ifa_ifwithaddr()` do not need this reference
     anymore, as epoch provides stability guarantee.
    
    Given that, update `in6ifa_ifwithaddr()` to allow
     it to return ifa without referencing it, while preserving
     option for getting referenced ifa if so desired.
    
    MFC after:              1 week
    Differential Revision:  https://reviews.freebsd.org/D28648
---
 sys/netinet/tcp_input.c     | 10 ++--------
 sys/netinet6/frag6.c        |  6 ++----
 sys/netinet6/icmp6.c        |  8 ++------
 sys/netinet6/in6.c          |  7 ++++---
 sys/netinet6/in6_ifattach.c |  4 +---
 sys/netinet6/in6_src.c      |  8 ++------
 sys/netinet6/in6_var.h      |  2 +-
 sys/netinet6/ip6_input.c    |  4 +---
 sys/netinet6/send.c         | 12 +++++++-----
 9 files changed, 22 insertions(+), 39 deletions(-)

diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 459b78cd444a..b7baef5bc0d6 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -592,16 +592,13 @@ tcp6_input(struct mbuf **mp, int *offp, int proto)
 	 * better place to put this in?
 	 */
 	ip6 = mtod(m, struct ip6_hdr *);
-	ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+	ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
 	if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
-		ifa_free(&ia6->ia_ifa);
 		icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR,
 			    (caddr_t)&ip6->ip6_dst - (caddr_t)ip6);
 		*mp = NULL;
 		return (IPPROTO_DONE);
 	}
-	if (ia6)
-		ifa_free(&ia6->ia_ifa);
 
 	*mp = m;
 	return (tcp_input(mp, offp, proto));
@@ -1249,10 +1246,9 @@ tfo_socket_result:
 		if (isipv6 && !V_ip6_use_deprecated) {
 			struct in6_ifaddr *ia6;
 
-			ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+			ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
 			if (ia6 != NULL &&
 			    (ia6->ia6_flags & IN6_IFF_DEPRECATED)) {
-				ifa_free(&ia6->ia_ifa);
 				if ((s = tcp_log_addrs(&inc, th, NULL, NULL)))
 				    log(LOG_DEBUG, "%s; %s: Listen socket: "
 					"Connection attempt to deprecated "
@@ -1261,8 +1257,6 @@ tfo_socket_result:
 				rstreason = BANDLIM_RST_OPENPORT;
 				goto dropwithreset;
 			}
-			if (ia6)
-				ifa_free(&ia6->ia_ifa);
 		}
 #endif /* INET6 */
 		/*
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
index c22e931dee33..f227930743b7 100644
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -396,11 +396,9 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
 
 	dstifp = NULL;
 	/* Find the destination interface of the packet. */
-	ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
-	if (ia6 != NULL) {
+	ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
+	if (ia6 != NULL)
 		dstifp = ia6->ia_ifp;
-		ifa_free(&ia6->ia_ifa);
-	}
 
 	/* Jumbo payload cannot contain a fragment header. */
 	if (ip6->ip6_plen == 0) {
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 6208b7be78a2..e17f82a54951 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -1221,19 +1221,17 @@ ni6_input(struct mbuf *m, int off, struct prison *pr)
 			goto bad;
 		/* else it's a link-local multicast, fine */
 	} else {		/* unicast or anycast */
-		ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+		ia6 = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
 		if (ia6 == NULL)
 			goto bad; /* XXX impossible */
 
 		if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) &&
 		    !(V_icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK)) {
-			ifa_free(&ia6->ia_ifa);
 			nd6log((LOG_DEBUG, "ni6_input: ignore node info to "
 				"a temporary address in %s:%d",
 			       __FILE__, __LINE__));
 			goto bad;
 		}
-		ifa_free(&ia6->ia_ifa);
 	}
 
 	/* validate query Subject field. */
@@ -2104,7 +2102,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
 	 * destined to a duplicated address of ours.
 	 */
 	if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
-		ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+		ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
 		if (ia != NULL && !(ia->ia6_flags &
 		    (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
 			src6 = ia->ia_addr.sin6_addr;
@@ -2116,8 +2114,6 @@ icmp6_reflect(struct mbuf *m, size_t off)
 			} else
 				hlim = V_ip6_defhlim;
 		}
-		if (ia != NULL)
-			ifa_free(&ia->ia_ifa);
 	}
 
 	if (srcp == NULL) {
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 057c0ee91e02..4665a21c28fd 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1550,10 +1550,10 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
 
 /*
  * find the interface address corresponding to a given IPv6 address.
- * ifaddr is returned referenced.
+ * ifaddr is returned referenced if @referenced flag is set.
  */
 struct in6_ifaddr *
-in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
+in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid, bool referenced)
 {
 	struct rm_priotracker in6_ifa_tracker;
 	struct in6_ifaddr *ia;
@@ -1564,7 +1564,8 @@ in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
 			if (zoneid != 0 &&
 			    zoneid != ia->ia_addr.sin6_scope_id)
 				continue;
-			ifa_ref(&ia->ia_ifa);
+			if (referenced)
+				ifa_ref(&ia->ia_ifa);
 			break;
 		}
 	}
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index 1a07fb13b179..02d6a2b230b4 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -713,11 +713,9 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
 		/*
 		 * check that loopback address doesn't exist yet.
 		 */
-		ia = in6ifa_ifwithaddr(&in6addr_loopback, 0);
+		ia = in6ifa_ifwithaddr(&in6addr_loopback, 0, false);
 		if (ia == NULL)
 			in6_ifattach_loopback(ifp);
-		else
-			ifa_free(&ia->ia_ifa);
 	}
 
 	/*
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 2224d568e121..7f623709de13 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -252,15 +252,11 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
 		 * ancillary data.
 		 */
 		if ((inp->inp_flags & INP_BINDANY) == 0) {
-			ia = in6ifa_ifwithaddr(&tmp, 0 /* XXX */);
+			ia = in6ifa_ifwithaddr(&tmp, 0 /* XXX */, false);
 			if (ia == NULL || (ia->ia6_flags & (IN6_IFF_ANYCAST |
-			    IN6_IFF_NOTREADY))) {
-				if (ia != NULL)
-					ifa_free(&ia->ia_ifa);
+			    IN6_IFF_NOTREADY)))
 				return (EADDRNOTAVAIL);
-			}
 			bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp));
-			ifa_free(&ia->ia_ifa);
 		} else
 			bcopy(&tmp, srcp, sizeof(*srcp));
 		pi->ipi6_addr = tmp; /* XXX: this overrides pi */
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index 5f4364c6fba0..1caa4511a2b1 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -899,7 +899,7 @@ void	in6_setmaxmtu(void);
 int	in6_if2idlen(struct ifnet *);
 struct in6_ifaddr *in6ifa_ifpforlinklocal(struct ifnet *, int);
 struct in6_ifaddr *in6ifa_ifpwithaddr(struct ifnet *, const struct in6_addr *);
-struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t);
+struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t, bool);
 struct in6_ifaddr *in6ifa_llaonifp(struct ifnet *);
 int	in6_addr2zoneid(struct ifnet *, struct in6_addr *, u_int32_t *);
 int	in6_matchlen(struct in6_addr *, struct in6_addr *);
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 8f500cb87bfe..80e5acc62548 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -803,7 +803,7 @@ passin:
 	 * XXX: For now we keep link-local IPv6 addresses with embedded
 	 *      scope zone id, therefore we use zero zoneid here.
 	 */
-	ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
+	ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */, false);
 	if (ia != NULL) {
 		if (ia->ia6_flags & IN6_IFF_NOTREADY) {
 			char ip6bufs[INET6_ADDRSTRLEN];
@@ -813,13 +813,11 @@ passin:
 			    "ip6_input: packet to an unready address %s->%s\n",
 			    ip6_sprintf(ip6bufs, &ip6->ip6_src),
 			    ip6_sprintf(ip6bufd, &ip6->ip6_dst)));
-			ifa_free(&ia->ia_ifa);
 			goto bad;
 		}
 		/* Count the packet in the ip address stats */
 		counter_u64_add(ia->ia_ifa.ifa_ipackets, 1);
 		counter_u64_add(ia->ia_ifa.ifa_ibytes, m->m_pkthdr.len);
-		ifa_free(&ia->ia_ifa);
 		ours = 1;
 		goto hbhcheck;
 	}
diff --git a/sys/netinet6/send.c b/sys/netinet6/send.c
index fbe53924c91f..0c839519b724 100644
--- a/sys/netinet6/send.c
+++ b/sys/netinet6/send.c
@@ -117,6 +117,7 @@ send_output(struct mbuf *m, struct ifnet *ifp, int direction)
 	struct icmp6_hdr *icmp6;
 	struct epoch_tracker et;
 	int icmp6len;
+	int error;
 
 	/*
 	 * Receive incoming (SeND-protected) or outgoing traffic
@@ -143,17 +144,17 @@ send_output(struct mbuf *m, struct ifnet *ifp, int direction)
 
 		ip6 = mtod(m, struct ip6_hdr *);
 		icmp6 = (struct icmp6_hdr *)(ip6 + 1);
+		error = 0;
 
 		/*
 		 * Output the packet as icmp6.c:icpm6_input() would do.
 		 * The mbuf is always consumed, so we do not have to
 		 * care about that.
 		 */
+		NET_EPOCH_ENTER(et);
 		switch (icmp6->icmp6_type) {
 		case ND_NEIGHBOR_SOLICIT:
-			NET_EPOCH_ENTER(et);
 			nd6_ns_input(m, sizeof(struct ip6_hdr), icmp6len);
-			NET_EPOCH_EXIT(et);
 			break;
 		case ND_NEIGHBOR_ADVERT:
 			nd6_na_input(m, sizeof(struct ip6_hdr), icmp6len);
@@ -169,9 +170,11 @@ send_output(struct mbuf *m, struct ifnet *ifp, int direction)
 			break;
 		default:
 			m_freem(m);
-			return (ENOSYS);
+			error = ENOSYS;
 		}
-		return (0);
+		NET_EPOCH_EXIT(et);
+
+		return (error);
 
 	case SND_OUT:
 		if (m->m_len < sizeof(struct ip6_hdr)) {
@@ -199,7 +202,6 @@ send_output(struct mbuf *m, struct ifnet *ifp, int direction)
 		 * XXX-BZ as we added data, what about fragmenting,
 		 * if now needed?
 		 */
-		int error;
 		error = ((*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
 		    NULL));
 		if (error)


More information about the dev-commits-src-all mailing list