#define DNS_ZONEFLG_THAW 0x08000000U
/* #define DNS_ZONEFLG_XXXXX 0x10000000U XXXMPA unused. */
#define DNS_ZONEFLG_NODELAY 0x20000000U
+#define DNS_ZONEFLG_NEEDSTARTUPNOTIFY 0x80000000U /*%< need to send out notify
+ * due to the zone just
+ * being loaded for the
+ * first time. */
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
#define DNS_ZONEKEY_OPTION(z,o) (((z)->keyopts & (o)) != 0)
isc_task_t * task;
isc_ratelimiter_t * notifyrl;
isc_ratelimiter_t * refreshrl;
+ isc_ratelimiter_t * startupnotifyrl;
+ isc_ratelimiter_t * startuprefreshrl;
isc_rwlock_t rwlock;
isc_mutex_t iolock;
isc_rwlock_t urlock;
/* Configuration data. */
isc_uint32_t transfersin;
isc_uint32_t transfersperns;
+ unsigned int notifyrate;
+ unsigned int startupnotifyrate;
unsigned int serialqueryrate;
+ unsigned int startupserialqueryrate;
/* Locked by iolock */
isc_uint32_t iolimit;
dns_name_t ns;
isc_sockaddr_t dst;
ISC_LINK(dns_notify_t) link;
+ isc_event_t *event;
};
#define DNS_NOTIFY_NOSOA 0x0001U
+#define DNS_NOTIFY_STARTUP 0x0002U
/*%
* dns_stub holds state while performing a 'stub' transfer.
dns_dbnode_t *node, dns_name_t *name,
dns_diff_t *diff);
static void zone_rekey(dns_zone_t *zone);
+static void setrl(isc_ratelimiter_t *rl, unsigned int *rate,
+ unsigned int value);
#define ENTER zone_debuglog(zone, me, 1, "enter")
zone_attachdb(zone, db);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
DNS_ZONE_SETFLAG(zone,
- DNS_ZONEFLG_LOADED|DNS_ZONEFLG_NEEDNOTIFY);
+ DNS_ZONEFLG_LOADED|
+ DNS_ZONEFLG_NEEDSTARTUPNOTIFY);
}
result = ISC_R_SUCCESS;
* Slaves send notifies before backing up to disk, masters after.
*/
if (zone->type == dns_zone_slave &&
- DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
+ (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) &&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
*/
switch (zone->type) {
case dns_zone_master:
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
+ if ((DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY)) &&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
default:
}
static isc_boolean_t
-notify_isqueued(dns_zone_t *zone, dns_name_t *name, isc_sockaddr_t *addr) {
+notify_isqueued(dns_zone_t *zone, unsigned int flags, dns_name_t *name,
+ isc_sockaddr_t *addr)
+{
dns_notify_t *notify;
+ dns_zonemgr_t *zmgr;
+ isc_result_t result;
for (notify = ISC_LIST_HEAD(zone->notifies);
notify != NULL;
notify = ISC_LIST_NEXT(notify, link)) {
if (notify->request != NULL)
continue;
+ if ((flags & DNS_NOTIFY_STARTUP) == 0)
+ notify->flags &= ~DNS_NOTIFY_STARTUP;
if (name != NULL && dns_name_dynamic(¬ify->ns) &&
dns_name_equal(name, ¬ify->ns))
- return (ISC_TRUE);
+ goto requeue;
if (addr != NULL && isc_sockaddr_equal(addr, ¬ify->dst))
- return (ISC_TRUE);
+ goto requeue;
}
return (ISC_FALSE);
+
+requeue:
+ /*
+ * If we are enqueued on the startup ratelimiter and this is
+ * not a startup notify, re-enqueue on the normal notify
+ * ratelimiter.
+ */
+ if (notify->event != NULL && (flags & DNS_NOTIFY_STARTUP) == 0) {
+ zmgr = notify->zone->zmgr;
+ result = isc_ratelimiter_dequeue(zmgr->startupnotifyrl,
+ notify->event);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_TRUE);
+ result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl,
+ notify->zone->task,
+ ¬ify->event);
+ if (result != ISC_R_SUCCESS) {
+ isc_event_free(¬ify->event);
+ return (ISC_FALSE);
+ }
+ }
+
+ return (ISC_TRUE);
}
static isc_boolean_t
notify->zone = NULL;
notify->find = NULL;
notify->request = NULL;
+ notify->event = NULL;
isc_sockaddr_any(¬ify->dst);
dns_name_init(¬ify->ns, NULL);
ISC_LINK_INIT(notify, link);
static isc_result_t
-notify_send_queue(dns_notify_t *notify) {
+notify_send_queue(dns_notify_t *notify, isc_boolean_t startup) {
isc_event_t *e;
isc_result_t result;
- e = isc_event_allocate(notify->mctx, NULL,
- DNS_EVENT_NOTIFYSENDTOADDR,
- notify_send_toaddr,
- notify, sizeof(isc_event_t));
+ INSIST(notify->event == NULL);
+ e = isc_event_allocate(notify->mctx, NULL, DNS_EVENT_NOTIFYSENDTOADDR,
+ notify_send_toaddr, notify, sizeof(isc_event_t));
if (e == NULL)
return (ISC_R_NOMEMORY);
+ if (startup)
+ notify->event = e;
e->ev_arg = notify;
e->ev_sender = NULL;
- result = isc_ratelimiter_enqueue(notify->zone->zmgr->notifyrl,
+ result = isc_ratelimiter_enqueue(startup
+ ? notify->zone->zmgr->startupnotifyrl
+ : notify->zone->zmgr->notifyrl,
notify->zone->task, &e);
- if (result != ISC_R_SUCCESS)
+ if (result != ISC_R_SUCCESS) {
isc_event_free(&e);
+ notify->event = NULL;
+ }
return (result);
}
LOCK_ZONE(notify->zone);
+ notify->event = NULL;
+
if (DNS_ZONE_FLAG(notify->zone, DNS_ZONEFLG_LOADED) == 0) {
result = ISC_R_CANCELED;
goto cleanup;
isc_sockaddr_t dst;
isc_result_t result;
dns_notify_t *new = NULL;
+ unsigned int flags;
+ isc_boolean_t startup;
/*
* Zone lock held by caller.
ai != NULL;
ai = ISC_LIST_NEXT(ai, publink)) {
dst = ai->sockaddr;
- if (notify_isqueued(notify->zone, NULL, &dst))
+ if (notify_isqueued(notify->zone, notify->flags, NULL, &dst))
continue;
if (notify_isself(notify->zone, &dst))
continue;
new = NULL;
- result = notify_create(notify->mctx,
- (notify->flags & DNS_NOTIFY_NOSOA),
- &new);
+ flags = notify->flags & DNS_NOTIFY_NOSOA;
+ result = notify_create(notify->mctx, flags, &new);
if (result != ISC_R_SUCCESS)
goto cleanup;
zone_iattach(notify->zone, &new->zone);
ISC_LIST_APPEND(new->zone->notifies, new, link);
new->dst = dst;
- result = notify_send_queue(new);
+ startup = ISC_TF((notify->flags & DNS_NOTIFY_STARTUP) != 0);
+ result = notify_send_queue(new, startup);
if (result != ISC_R_SUCCESS)
goto cleanup;
new = NULL;
dns_notifytype_t notifytype;
unsigned int flags = 0;
isc_boolean_t loggednotify = ISC_FALSE;
+ isc_boolean_t startup;
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
+ startup = !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY);
notifytype = zone->notifytype;
DNS_ZONE_TIME_ADD(now, zone->notifydelay, &zone->notifytime);
UNLOCK_ZONE(zone);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DIALNOTIFY))
flags |= DNS_NOTIFY_NOSOA;
+ /*
+ * Record that this was a notify due to starting up.
+ */
+ if (startup)
+ flags |= DNS_NOTIFY_STARTUP;
+
/*
* Get SOA RRset.
*/
LOCK_ZONE(zone);
for (i = 0; i < zone->notifycnt; i++) {
dst = zone->notify[i];
- if (notify_isqueued(zone, NULL, &dst))
+ if (notify_isqueued(zone, flags, NULL, &dst))
continue;
result = notify_create(zone->mctx, flags, ¬ify);
if (result != ISC_R_SUCCESS)
zone_iattach(zone, ¬ify->zone);
notify->dst = dst;
ISC_LIST_APPEND(zone->notifies, notify, link);
- result = notify_send_queue(notify);
+ result = notify_send_queue(notify, startup);
if (result != ISC_R_SUCCESS)
notify_destroy(notify, ISC_TRUE);
if (!loggednotify) {
}
LOCK_ZONE(zone);
- isqueued = notify_isqueued(zone, &ns.name, NULL);
+ isqueued = notify_isqueued(zone, flags, &ns.name, NULL);
UNLOCK_ZONE(zone);
if (isqueued) {
result = dns_rdataset_next(&nsrdset);
switch (zone->type) {
case dns_zone_master:
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY))
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) ||
+ DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDSTARTUPNOTIFY))
next = zone->notifytime;
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDDUMP) &&
!DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING)) {
isc_event_free(&event);
if (message != NULL && message->rcode == dns_rcode_formerr &&
(notify->flags & DNS_NOTIFY_NOSOA) == 0) {
+ isc_boolean_t startup;
+
notify->flags |= DNS_NOTIFY_NOSOA;
dns_request_destroy(¬ify->request);
- result = notify_send_queue(notify);
+ startup = ISC_TF((notify->flags & DNS_NOTIFY_STARTUP) != 0);
+ result = notify_send_queue(notify, startup);
if (result != ISC_R_SUCCESS)
notify_destroy(notify, ISC_FALSE);
} else {
{
dns_zonemgr_t *zmgr;
isc_result_t result;
- isc_interval_t interval;
zmgr = isc_mem_get(mctx, sizeof(*zmgr));
if (zmgr == NULL)
zmgr->task = NULL;
zmgr->notifyrl = NULL;
zmgr->refreshrl = NULL;
+ zmgr->startupnotifyrl = NULL;
+ zmgr->startuprefreshrl = NULL;
ISC_LIST_INIT(zmgr->zones);
ISC_LIST_INIT(zmgr->waiting_for_xfrin);
ISC_LIST_INIT(zmgr->xfrin_in_progress);
if (result != ISC_R_SUCCESS)
goto free_notifyrl;
- /* default to 20 refresh queries / notifies per second. */
- isc_interval_set(&interval, 0, 1000000000/2);
- result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_ratelimiter_setpertic(zmgr->notifyrl, 10);
+ result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
+ &zmgr->startupnotifyrl);
+ if (result != ISC_R_SUCCESS)
+ goto free_refreshrl;
- result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_ratelimiter_setpertic(zmgr->refreshrl, 10);
+ result = isc_ratelimiter_create(mctx, timermgr, zmgr->task,
+ &zmgr->startuprefreshrl);
+ if (result != ISC_R_SUCCESS)
+ goto free_startupnotifyrl;
+
+ /* default to 20 refresh queries / notifies per second. */
+ setrl(zmgr->notifyrl, &zmgr->notifyrate, 20);
+ setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20);
+ setrl(zmgr->refreshrl, &zmgr->serialqueryrate, 20);
+ setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, 20);
zmgr->iolimit = 1;
zmgr->ioactive = 0;
result = isc_mutex_init(&zmgr->iolock);
if (result != ISC_R_SUCCESS)
- goto free_refreshrl;
+ goto free_startuprefreshrl;
zmgr->magic = ZONEMGR_MAGIC;
free_iolock:
DESTROYLOCK(&zmgr->iolock);
#endif
+ free_startuprefreshrl:
+ isc_ratelimiter_detach(&zmgr->startuprefreshrl);
+ free_startupnotifyrl:
+ isc_ratelimiter_detach(&zmgr->startupnotifyrl);
free_refreshrl:
isc_ratelimiter_detach(&zmgr->refreshrl);
free_notifyrl:
isc_ratelimiter_shutdown(zmgr->notifyrl);
isc_ratelimiter_shutdown(zmgr->refreshrl);
+ isc_ratelimiter_shutdown(zmgr->startupnotifyrl);
+ isc_ratelimiter_shutdown(zmgr->startuprefreshrl);
if (zmgr->task != NULL)
isc_task_destroy(&zmgr->task);
DESTROYLOCK(&zmgr->iolock);
isc_ratelimiter_detach(&zmgr->notifyrl);
isc_ratelimiter_detach(&zmgr->refreshrl);
+ isc_ratelimiter_detach(&zmgr->startupnotifyrl);
+ isc_ratelimiter_detach(&zmgr->startuprefreshrl);
isc_rwlock_destroy(&zmgr->urlock);
isc_rwlock_destroy(&zmgr->rwlock);
}
#endif
-void
-dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
+static void
+setrl(isc_ratelimiter_t *rl, unsigned int *rate, unsigned int value) {
isc_interval_t interval;
isc_uint32_t s, ns;
isc_uint32_t pertic;
isc_result_t result;
- REQUIRE(DNS_ZONEMGR_VALID(zmgr));
-
if (value == 0)
value = 1;
isc_interval_set(&interval, s, ns);
- result = isc_ratelimiter_setinterval(zmgr->notifyrl, &interval);
+ result = isc_ratelimiter_setinterval(rl, &interval);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_ratelimiter_setpertic(zmgr->notifyrl, pertic);
+ isc_ratelimiter_setpertic(rl, pertic);
- result = isc_ratelimiter_setinterval(zmgr->refreshrl, &interval);
- RUNTIME_CHECK(result == ISC_R_SUCCESS);
- isc_ratelimiter_setpertic(zmgr->refreshrl, pertic);
+ *rate = value;
+}
+
+void
+dns_zonemgr_setserialqueryrate(dns_zonemgr_t *zmgr, unsigned int value) {
+
+ REQUIRE(DNS_ZONEMGR_VALID(zmgr));
+
+ setrl(zmgr->refreshrl, &zmgr->serialqueryrate, value);
+
+ /* Seperately controlled in BIND 9.11.x */
+ setrl(zmgr->notifyrl, &zmgr->notifyrate, 20);
+ setrl(zmgr->startupnotifyrl, &zmgr->startupnotifyrate, 20);
- zmgr->serialqueryrate = value;
+ /* XXXMPA seperate out once we have the code to support this. */
+ setrl(zmgr->startuprefreshrl, &zmgr->startupserialqueryrate, value);
}
unsigned int