+
+/*
+ * Called as part of ip_init
+ */
+void
+in_ifaddr_init(void)
+{
+ PE_parse_boot_argn("ifa_debug", &inifa_debug, sizeof (inifa_debug));
+
+ inifa_size = (inifa_debug == 0) ? sizeof (struct in_ifaddr) :
+ sizeof (struct in_ifaddr_dbg);
+
+ inifa_zone = zinit(inifa_size, INIFA_ZONE_MAX * inifa_size,
+ 0, INIFA_ZONE_NAME);
+ if (inifa_zone == NULL)
+ panic("%s: failed allocating %s", __func__, INIFA_ZONE_NAME);
+
+ zone_change(inifa_zone, Z_EXPAND, TRUE);
+}
+
+static struct in_ifaddr *
+in_ifaddr_alloc(int how)
+{
+ struct in_ifaddr *inifa;
+
+ inifa = (how == M_WAITOK) ? zalloc(inifa_zone) :
+ zalloc_noblock(inifa_zone);
+ if (inifa != NULL) {
+ bzero(inifa, inifa_size);
+ inifa->ia_ifa.ifa_free = in_ifaddr_free;
+ inifa->ia_ifa.ifa_debug |= IFD_ALLOC;
+ if (inifa_debug != 0) {
+ struct in_ifaddr_dbg *inifa_dbg =
+ (struct in_ifaddr_dbg *)inifa;
+ inifa->ia_ifa.ifa_debug |= IFD_DEBUG;
+ inifa->ia_ifa.ifa_trace = in_ifaddr_trace;
+ ctrace_record(&inifa_dbg->inifa_alloc);
+ }
+ }
+ return (inifa);
+}
+
+static void
+in_ifaddr_free(struct ifaddr *ifa)
+{
+ if (ifa->ifa_refcnt != 0)
+ panic("%s: ifa %p bad ref cnt", __func__, ifa);
+ if (!(ifa->ifa_debug & IFD_ALLOC))
+ panic("%s: ifa %p cannot be freed", __func__, ifa);
+
+ if (ifa->ifa_debug & IFD_DEBUG) {
+ struct in_ifaddr_dbg *inifa_dbg = (struct in_ifaddr_dbg *)ifa;
+ ctrace_record(&inifa_dbg->inifa_free);
+ bcopy(&inifa_dbg->inifa, &inifa_dbg->inifa_old,
+ sizeof (struct in_ifaddr));
+ }
+ bzero(ifa, sizeof (struct in_ifaddr));
+ zfree(inifa_zone, ifa);
+}
+
+static void
+in_ifaddr_trace(struct ifaddr *ifa, int refhold)
+{
+ struct in_ifaddr_dbg *inifa_dbg = (struct in_ifaddr_dbg *)ifa;
+ ctrace_t *tr;
+ u_int32_t idx;
+ u_int16_t *cnt;
+
+ if (!(ifa->ifa_debug & IFD_DEBUG))
+ panic("%s: ifa %p has no debug structure", __func__, ifa);
+
+ if (refhold) {
+ cnt = &inifa_dbg->inifa_refhold_cnt;
+ tr = inifa_dbg->inifa_refhold;
+ } else {
+ cnt = &inifa_dbg->inifa_refrele_cnt;
+ tr = inifa_dbg->inifa_refrele;
+ }
+
+ idx = OSAddAtomic16(1, (volatile SInt16 *)cnt) % CTRACE_HIST_SIZE;
+ ctrace_record(&tr[idx]);
+}