Index: contrib/ipfilter/tools/ipftest.c =================================================================== --- contrib/ipfilter/tools/ipftest.c +++ contrib/ipfilter/tools/ipftest.c @@ -865,10 +865,18 @@ } } +unsigned +ip_initid(void) +{ + return (0); +} + void -ip_fillid(struct ip *ip) +ip_fillid(struct ip *ip, unsigned *pid) { static uint16_t ip_id; - - ip->ip_id = ip_id++; + if (pid != NULL) + ip->ip_id = (*pid)++ + else + ip->ip_id = ip_id++; } Index: sys/contrib/ipfilter/netinet/fil.c =================================================================== --- sys/contrib/ipfilter/netinet/fil.c +++ sys/contrib/ipfilter/netinet/fil.c @@ -6096,7 +6096,7 @@ id = (u_short)sum; ip->ip_id = htons(id); } else { - ip_fillid(ip); + ip_fillid(ip, NULL); id = ntohs(ip->ip_id); if ((fin->fin_flx & FI_FRAG) != 0) (void) ipf_frag_ipidnew(fin, (u_32_t)id); Index: sys/contrib/ipfilter/netinet/ip_fil.h =================================================================== --- sys/contrib/ipfilter/netinet/ip_fil.h +++ sys/contrib/ipfilter/netinet/ip_fil.h @@ -1718,7 +1718,8 @@ extern void m_freem __P((mb_t *)); extern size_t msgdsize __P((mb_t *)); extern int bcopywrap __P((void *, void *, size_t)); -extern void ip_fillid(struct ip *); +extern unsigned ip_initid(void); +extern void ip_fillid(struct ip *, unsigned *); #else /* #ifndef _KERNEL */ # if defined(__NetBSD__) && defined(PFIL_HOOKS) extern void ipfilterattach __P((int)); Index: sys/contrib/ipfilter/netinet/ip_nat.h =================================================================== --- sys/contrib/ipfilter/netinet/ip_nat.h +++ sys/contrib/ipfilter/netinet/ip_nat.h @@ -661,6 +661,7 @@ ipftq_t ipf_nat_pending; ipftq_t ipf_nat_tcptq[IPF_TCP_NSTATES]; natstat_t ipf_nat_stats; + unsigned ipf_nat_ip_id; /* IP ID number */ } ipf_nat_softc_t ; #define ipf_nat_map_max ipf_nat_map_mask.imt4_max Index: sys/contrib/ipfilter/netinet/ip_nat.c =================================================================== --- sys/contrib/ipfilter/netinet/ip_nat.c +++ sys/contrib/ipfilter/netinet/ip_nat.c @@ -319,6 +319,7 @@ bzero((char *)softn, sizeof(*softn)); + softn->ipf_nat_ip_id = ip_initid(); softn->ipf_nat_tune = ipf_tune_array_copy(softn, sizeof(ipf_nat_tuneables), ipf_nat_tuneables); @@ -5221,7 +5222,7 @@ } ip = MTOD(m, ip_t *); - ip_fillid(ip); + ip_fillid(ip, &softn->ipf_nat_ip_id); s2 = ntohs(ip->ip_id); s1 = ip->ip_len; Index: sys/net/if_gre.h =================================================================== --- sys/net/if_gre.h +++ sys/net/if_gre.h @@ -82,6 +82,7 @@ #endif } gre_uhdr; const struct encaptab *gre_ecookie; + unsigned gre_ip_id; /* IP ID number */ }; #define GRE2IFP(sc) ((sc)->gre_ifp) #define GRE_LOCK_INIT(sc) rm_init(&(sc)->gre_lock, "gre softc") @@ -103,7 +104,7 @@ int gre_input(struct mbuf **, int *, int); #ifdef INET int in_gre_attach(struct gre_softc *); -int in_gre_output(struct mbuf *, int, int); +int in_gre_output(struct gre_softc *, struct mbuf *, int, int); #endif #ifdef INET6 int in6_gre_attach(struct gre_softc *); Index: sys/net/if_gre.c =================================================================== --- sys/net/if_gre.c +++ sys/net/if_gre.c @@ -909,7 +909,7 @@ switch (oaf) { #ifdef INET case AF_INET: - error = in_gre_output(m, iaf, hlen); + error = in_gre_output(sc, m, iaf, hlen); break; #endif #ifdef INET6 Index: sys/netinet/in_pcb.h =================================================================== --- sys/netinet/in_pcb.h +++ sys/netinet/in_pcb.h @@ -220,6 +220,7 @@ struct llentry *inp_lle; /* cached L2 information */ struct rtentry *inp_rt; /* cached L3 information */ struct rwlock inp_lock; + unsigned inp_ip_id; /* (i) IP ID number */ }; #define inp_fport inp_inc.inc_fport #define inp_lport inp_inc.inc_lport Index: sys/netinet/in_pcb.c =================================================================== --- sys/netinet/in_pcb.c +++ sys/netinet/in_pcb.c @@ -280,6 +280,7 @@ if (inp == NULL) return (ENOBUFS); bzero(inp, inp_zero_size); + inp->inp_ip_id = ip_initid(); inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; inp->inp_cred = crhold(so->so_cred); Index: sys/netinet/ip_carp.c =================================================================== --- sys/netinet/ip_carp.c +++ sys/netinet/ip_carp.c @@ -118,6 +118,8 @@ int sc_init_counter; uint64_t sc_counter; + unsigned sc_ip_id; /* IP ID number */ + /* authentication */ #define CARP_HMAC_PAD 64 unsigned char sc_key[CARP_KEY_LEN]; @@ -842,7 +844,7 @@ ip->ip_ttl = CARP_DFLTTL; ip->ip_p = IPPROTO_CARP; ip->ip_sum = 0; - ip_fillid(ip); + ip_fillid(ip, &sc->sc_ip_id); bzero(&sa, sizeof(sa)); sa.sa_family = AF_INET; @@ -1477,6 +1479,7 @@ sc = malloc(sizeof(*sc), M_CARP, M_WAITOK|M_ZERO); + sc->sc_ip_id = ip_initid(); sc->sc_advbase = CARP_DFLTINTV; sc->sc_vhid = -1; /* required setting */ sc->sc_init_counter = 1; Index: sys/netinet/ip_gre.c =================================================================== --- sys/netinet/ip_gre.c +++ sys/netinet/ip_gre.c @@ -125,7 +125,7 @@ } int -in_gre_output(struct mbuf *m, int af, int hlen) +in_gre_output(struct gre_softc *sc, struct mbuf *m, int af, int hlen) { struct greip *gi; @@ -145,7 +145,7 @@ #ifdef INET6 case AF_INET6: gi->gi_ip.ip_tos = 0; /* XXX */ - ip_fillid(&gi->gi_ip); + ip_fillid(&gi->gi_ip, &sc->gre_ip_id); break; #endif } Index: sys/netinet/ip_id.c =================================================================== --- sys/netinet/ip_id.c +++ sys/netinet/ip_id.c @@ -124,7 +124,7 @@ /* * Non-random ID state engine is simply a per-cpu counter. */ -static VNET_DEFINE(counter_u64_t, ip_id); +static VNET_DEFINE(unsigned, ip_id); #define V_ip_id VNET(ip_id) static int sysctl_ip_randomid(SYSCTL_HANDLER_ARGS); @@ -238,8 +238,16 @@ return (new_id); } +unsigned +ip_initid(void) +{ + unsigned temp = 0; + arc4rand(&temp, sizeof(temp), 0); + return (temp); +} + void -ip_fillid(struct ip *ip) +ip_fillid(struct ip *ip, unsigned *pid) { /* @@ -252,23 +260,12 @@ ip->ip_id = 0; else if (V_ip_do_randomid) ip->ip_id = ip_randomid(); - else { - counter_u64_add(V_ip_id, 1); - /* - * There are two issues about this trick, to be kept in mind. - * 1) We can migrate between counter_u64_add() and next - * line, and grab counter from other CPU, resulting in too - * quick ID reuse. This is tolerable in our particular case, - * since probability of such event is much lower then reuse - * of ID due to legitimate overflow, that at modern Internet - * speeds happens all the time. - * 2) We are relying on the fact that counter(9) is based on - * UMA_ZONE_PCPU uma(9) zone. We also take only last - * sixteen bits of a counter, so we don't care about the - * fact that machines with 32-bit word update their counters - * not atomically. - */ - ip->ip_id = htons((*(uint64_t *)zpcpu_get(V_ip_id)) & 0xffff); + else if (pid != NULL) { + /* no need to byteswap IP ID field */ + ip->ip_id = atomic_fetchadd_int(pid, 1) & 0xFFFF; + } else { /* fallback to global IP ID counter */ + /* no need to byteswap IP ID field */ + ip->ip_id = atomic_fetchadd_int(&V_ip_id, 1) & 0xFFFF; } } @@ -277,9 +274,7 @@ { mtx_init(&V_ip_id_mtx, "ip_id_mtx", NULL, MTX_DEF); - V_ip_id = counter_u64_alloc(M_WAITOK); - for (int i = 0; i < mp_ncpus; i++) - arc4rand(zpcpu_get_cpu(V_ip_id, i), sizeof(uint64_t), 0); + V_ip_id = ip_initid(); } VNET_SYSINIT(ip_id, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, ipid_sysinit, NULL); @@ -292,6 +287,5 @@ free(V_id_array, M_IPID); free(V_id_bits, M_IPID); } - counter_u64_free(V_ip_id); } VNET_SYSUNINIT(ip_id, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY, ipid_sysuninit, NULL); Index: sys/netinet/ip_mroute.h =================================================================== --- sys/netinet/ip_mroute.h +++ sys/netinet/ip_mroute.h @@ -263,6 +263,7 @@ u_long v_pkt_out; /* # pkts out on interface */ u_long v_bytes_in; /* # bytes in on interface */ u_long v_bytes_out; /* # bytes out on interface */ + unsigned v_ip_id; /* IP ID number */ }; #ifdef _KERNEL Index: sys/netinet/ip_mroute.c =================================================================== --- sys/netinet/ip_mroute.c +++ sys/netinet/ip_mroute.c @@ -920,6 +920,8 @@ vifp->v_pkt_out = 0; vifp->v_bytes_in = 0; vifp->v_bytes_out = 0; + /* setup default IP ID */ + vifp->v_ip_id = ip_initid(); /* Adjust numvifs up if the vifi is higher than numvifs */ if (V_numvifs <= vifcp->vifc_vifi) @@ -2512,7 +2514,7 @@ ip_outer->ip_tos = ip->ip_tos; if (ip->ip_off & htons(IP_DF)) ip_outer->ip_off |= htons(IP_DF); - ip_fillid(ip_outer); + ip_fillid(ip_outer, &vifp->v_ip_id); pimhdr = (struct pim_encap_pimhdr *)((caddr_t)ip_outer + sizeof(pim_encap_iphdr)); *pimhdr = pim_encap_pimhdr; Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c +++ sys/netinet/ip_output.c @@ -175,7 +175,7 @@ if ((flags & (IP_FORWARDING|IP_RAWOUTPUT)) == 0) { ip->ip_v = IPVERSION; ip->ip_hl = hlen >> 2; - ip_fillid(ip); + ip_fillid(ip, (inp != NULL) ? &inp->inp_ip_id : NULL); IPSTAT_INC(ips_localout); } else { /* Header already set, fetch hlen from there */ Index: sys/netinet/ip_var.h =================================================================== --- sys/netinet/ip_var.h +++ sys/netinet/ip_var.h @@ -227,7 +227,8 @@ void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *, struct mbuf *); void ip_slowtimo(void); -void ip_fillid(struct ip *); +unsigned ip_initid(void); +void ip_fillid(struct ip *, unsigned *); int rip_ctloutput(struct socket *, struct sockopt *); void rip_ctlinput(int, struct sockaddr *, void *); void rip_init(void); Index: sys/netinet/raw_ip.c =================================================================== --- sys/netinet/raw_ip.c +++ sys/netinet/raw_ip.c @@ -510,7 +510,7 @@ * but we got this limitation from the beginning of history. */ if (ip->ip_id == 0) - ip_fillid(ip); + ip_fillid(ip, &inp->inp_ip_id); /* * XXX prevent ip_output from overwriting header fields. Index: sys/netinet/sctp_output.c =================================================================== --- sys/netinet/sctp_output.c +++ sys/netinet/sctp_output.c @@ -4106,7 +4106,7 @@ ip->ip_off = htons(0); } /* FreeBSD has a function for ip_id's */ - ip_fillid(ip); + ip_fillid(ip, &inp->inp.inp_ip_id); ip->ip_ttl = inp->ip_inp.inp.inp_ip_ttl; ip->ip_len = htons(packet_length); @@ -10950,7 +10950,7 @@ ip->ip_hl = (sizeof(struct ip) >> 2); ip->ip_tos = 0; ip->ip_off = 0; - ip_fillid(ip); + ip_fillid(ip, NULL); ip->ip_ttl = MODULE_GLOBAL(ip_defttl); if (port) { ip->ip_p = IPPROTO_UDP; Index: sys/netinet/sctp_pcb.c =================================================================== --- sys/netinet/sctp_pcb.c +++ sys/netinet/sctp_pcb.c @@ -2458,6 +2458,9 @@ /* zap it */ bzero(inp, sizeof(*inp)); + /* setup default IP ID */ + inp->ip_inp.inp_ip_id = ip_initid(); + /* bump generations */ /* setup socket pointers */ inp->sctp_socket = so; Index: sys/netipsec/xform_ipip.c =================================================================== --- sys/netipsec/xform_ipip.c +++ sys/netipsec/xform_ipip.c @@ -175,7 +175,7 @@ default: goto nofamily; } - ip_fillid(ipo); + ip_fillid(ipo, NULL); otos = 0; ip_ecn_ingress(ECN_ALLOWED, &otos, &itos); Index: sys/netpfil/pf/if_pfsync.c =================================================================== --- sys/netpfil/pf/if_pfsync.c +++ sys/netpfil/pf/if_pfsync.c @@ -214,6 +214,7 @@ uint32_t sc_bulk_creatorid; struct callout sc_bulk_tmo; struct callout sc_bulkfail_tmo; + unsigned sc_ip_id; /* IP ID number */ }; #define PFSYNC_LOCK(sc) mtx_lock(&(sc)->sc_mtx) @@ -298,6 +299,7 @@ return (EINVAL); sc = malloc(sizeof(struct pfsync_softc), M_PFSYNC, M_WAITOK | M_ZERO); + sc->sc_ip_id = ip_initid(); sc->sc_flags |= PFSYNCF_OK; for (q = 0; q < PFSYNC_S_COUNT; q++) @@ -1538,7 +1540,7 @@ offset = sizeof(*ip); ip->ip_len = htons(m->m_pkthdr.len); - ip_fillid(ip); + ip_fillid(ip, &sc->sc_ip_id); /* build the pfsync header */ ph = (struct pfsync_header *)(m->m_data + offset); Index: sys/netpfil/pf/pf_norm.c =================================================================== --- sys/netpfil/pf/pf_norm.c +++ sys/netpfil/pf/pf_norm.c @@ -2273,7 +2273,7 @@ if (flags & PFRULE_RANDOMID && !(h->ip_off & ~htons(IP_DF))) { uint16_t ip_id = h->ip_id; - ip_fillid(h); + ip_fillid(h, NULL); h->ip_sum = pf_cksum_fixup(h->ip_sum, ip_id, h->ip_id, 0); } }