svn commit: r184096 - in head/sys: netinet netinet6
Bjoern A. Zeeb
bz at FreeBSD.org
Mon Oct 20 18:44:00 UTC 2008
Author: bz
Date: Mon Oct 20 18:43:59 2008
New Revision: 184096
URL: http://svn.freebsd.org/changeset/base/184096
Log:
Bring over the change switching from using sequential to random
ephemeral port allocation as implemented in netinet/in_pcb.c rev. 1.143
(initially from OpenBSD) and follow-up commits during the last four and
a half years including rev. 1.157, 1.162 and 1.199.
This now is relying on the same infrastructure as has been implemented
in in_pcb.c since rev. 1.199.
Reviewed by: silby, rpaulo, mlaier
MFC after: 2 months
Modified:
head/sys/netinet/in_pcb.h
head/sys/netinet6/in6_src.c
Modified: head/sys/netinet/in_pcb.h
==============================================================================
--- head/sys/netinet/in_pcb.h Mon Oct 20 18:37:10 2008 (r184095)
+++ head/sys/netinet/in_pcb.h Mon Oct 20 18:43:59 2008 (r184096)
@@ -449,6 +449,9 @@ extern int ipport_firstauto;
extern int ipport_lastauto;
extern int ipport_hifirstauto;
extern int ipport_hilastauto;
+extern int ipport_randomized;
+extern int ipport_stoprandom;
+extern int ipport_tcpallocs;
extern struct callout ipport_tick_callout;
void in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
Modified: head/sys/netinet6/in6_src.c
==============================================================================
--- head/sys/netinet6/in6_src.c Mon Oct 20 18:37:10 2008 (r184095)
+++ head/sys/netinet6/in6_src.c Mon Oct 20 18:43:59 2008 (r184096)
@@ -95,6 +95,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
#include <netinet6/in6_var.h>
#include <netinet/ip6.h>
#include <netinet6/in6_pcb.h>
@@ -774,7 +777,7 @@ in6_pcbsetport(struct in6_addr *laddr, s
INIT_VNET_INET(curvnet);
struct socket *so = inp->inp_socket;
u_int16_t lport = 0, first, last, *lastport;
- int count, error = 0, wild = 0;
+ int count, error = 0, wild = 0, dorandom;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
INP_INFO_WLOCK_ASSERT(pcbinfo);
@@ -802,56 +805,58 @@ in6_pcbsetport(struct in6_addr *laddr, s
last = V_ipport_lastauto;
lastport = &pcbinfo->ipi_lastport;
}
+
/*
- * Simple check to ensure all ports are not used up causing
- * a deadlock here.
- *
- * We split the two cases (up and down) so that the direction
- * is not being tested on each round of the loop.
+ * For UDP, use random port allocation as long as the user
+ * allows it. For TCP (and as of yet unknown) connections,
+ * use random port allocation only if the user allows it AND
+ * ipport_tick() allows it.
*/
- if (first > last) {
- /*
- * counting down
- */
- count = first - last;
+ if (V_ipport_randomized &&
+ (!V_ipport_stoprandom || pcbinfo == &V_udbinfo))
+ dorandom = 1;
+ else
+ dorandom = 0;
+ /*
+ * It makes no sense to do random port allocation if
+ * we have the only port available.
+ */
+ if (first == last)
+ dorandom = 0;
+ /* Make sure to not include UDP packets in the count. */
+ if (pcbinfo != &V_udbinfo)
+ V_ipport_tcpallocs++;
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- --*lastport;
- if (*lastport > first || *lastport < last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
- lport, wild, cred));
- } else {
- /*
- * counting up
- */
- count = last - first;
+ /*
+ * Instead of having two loops further down counting up or down
+ * make sure that first is always <= last and go with only one
+ * code path implementing all logic.
+ */
+ if (first > last) {
+ u_int16_t aux;
- do {
- if (count-- < 0) { /* completely used? */
- /*
- * Undo any address bind that may have
- * occurred above.
- */
- inp->in6p_laddr = in6addr_any;
- return (EAGAIN);
- }
- ++*lastport;
- if (*lastport < first || *lastport > last)
- *lastport = first;
- lport = htons(*lastport);
- } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
- lport, wild, cred));
- }
+ aux = first;
+ first = last;
+ last = aux;
+ }
+
+ if (dorandom)
+ *lastport = first + (arc4random() % (last - first));
+
+ count = last - first;
+
+ do {
+ if (count-- < 0) { /* completely used? */
+ /* Undo an address bind that may have occurred. */
+ inp->in6p_laddr = in6addr_any;
+ return (EADDRNOTAVAIL);
+ }
+ ++*lastport;
+ if (*lastport < first || *lastport > last)
+ *lastport = first;
+ lport = htons(*lastport);
+ } while (in6_pcblookup_local(pcbinfo, &inp->in6p_laddr,
+ lport, wild, cred));
inp->inp_lport = lport;
if (in_pcbinshash(inp) != 0) {
More information about the svn-src-head
mailing list