1 /* Copyright © 2012 Brandon L Black <blblack@gmail.com>
2 *
3 * This file is part of gdnsd.
4 *
5 * gdnsd is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * gdnsd is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with gdnsd. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #ifndef GDNSD_MON_H
21 #define GDNSD_MON_H
22
23 #include <gdnsd/compiler.h>
24 #include <gdnsd/net.h>
25 #include <gdnsd/prcu.h>
26
27 #include <inttypes.h>
28
29 // gdnsd_sttl_t
30 // sttl -> state+ttl
31 // high-bit is down flag (1 = down, 0 = up)
32 // next-bit is forced flag (1 = forced, 0 = unforced)
33 // next 2 bits reserved for future use (set to zero, ignored on read)
34 // remaining 28 bits are unsigned TTL (max value ~8.5 years)
35 typedef uint32_t gdnsd_sttl_t;
36
37 static const gdnsd_sttl_t GDNSD_STTL_DOWN = (1U << 31U);
38 static const gdnsd_sttl_t GDNSD_STTL_FORCED = (1U << 30U);
39 static const gdnsd_sttl_t GDNSD_STTL_RESERVED_MASK = (3U << 28U);
40 static const gdnsd_sttl_t GDNSD_STTL_TTL_MASK = ((1U << 28U) - 1U);
41 static const gdnsd_sttl_t GDNSD_STTL_TTL_MAX = ((1U << 28U) - 1U);
42 // ^ identical to above, but better semantics when reading code
43
44 // the only hard rule on this data type is zero in the reserved bits for now
45 #define assert_valid_sttl(_x) dmn_assert(!((_x) & GDNSD_STTL_RESERVED_MASK))
46
47 #pragma GCC visibility push(default)
48
49 // Parses a string of the form STATE[/TTL], where STATE is UP or DOWN and
50 // the TTL is in the legal range 0 through 2^28-1. Returns 0 on success.
51 // This is exported mostly so that it can be shared with plugin_extfile,
52 // I don't know if anything else will ever use it.
53 F_NONNULL
54 bool gdnsd_mon_parse_sttl(const char* sttl_str, gdnsd_sttl_t* sttl_out, unsigned def_ttl);
55
56 // sttl log formatter's output looks like:
57 // "DOWN/1234(FORCED)"
58 // where (FORCED) is only present on the forced flag,
59 // and the special TTLs 0 and 268435455 are given
60 // as the strings "MIN" and "MAX" for clarity.
61 const char* gdnsd_logf_sttl(const gdnsd_sttl_t s);
62 #define logf_sttl gdnsd_logf_sttl
63
64 // A simple monitoring plugins calls this helper after every raw
65 // state check of a monitored address. The core tracks long
66 // term state history for anti-flap and calculates TTLs on
67 // the assumption the plugin is using the provided intervals
68 // and has no deeper information than the immediate check result.
69 // latest -> 0 failed, 1 succeeded
70 void gdnsd_mon_state_updater(unsigned idx, const bool latest);
71
72 // A more-advanced monitoring plugin may wish to do its own
73 // anti-flap state-tracking and TTL-calculations, in which
74 // case it can use this interface to provide full, direct updates.
75 // NOTE: it is not legal for any monitoring plugin to set the FORCED
76 // bit in "new_sttl" - this is checked as an assertion!
77 void gdnsd_mon_sttl_updater(unsigned idx, gdnsd_sttl_t new_sttl);
78
79 // called during load_config to register address healthchecks, returns
80 // an index to check state with...
81 F_NONNULL
82 unsigned gdnsd_mon_addr(const char* svctype_name, const dmn_anysin_t* addr);
83
84 // as above for a CNAME
85 F_NONNULL
86 unsigned gdnsd_mon_cname(const char* svctype_name, const char* cname, const uint8_t* dname);
87
88 // admin-only state registration. plugin constructs desc
89 // within its own scope, e.g.
90 // "plugname/resname/dcname" for a datacenter virtual.
91 // it is up to the plugin to ensure uniqueness here...
92 F_NONNULL
93 unsigned gdnsd_mon_admin(const char* desc);
94
95 // do not ref this directly in a plugin!
96 // use gdnsd_mon_get_sttl_table() below for access!
97 extern gdnsd_sttl_t* smgr_sttl_consumer_;
98
99 #pragma GCC visibility pop
100
101 // State-fetching (one table call per resolve invocation, reused
102 // for as many index fetches as necc)
103 F_UNUSED
gdnsd_mon_get_sttl_table(void)104 static const gdnsd_sttl_t* gdnsd_mon_get_sttl_table(void) {
105 return gdnsd_prcu_rdr_deref(smgr_sttl_consumer_);
106 }
107
108 // Given two sttl values, combine them according to the following rules:
109 // 1) result TTL is the lesser of both TTLs
110 // 2) if either is down, result is down
111 // 3) if either is forced, result is forced
112 // This is meant to be used to combine parallel results, e.g. two
113 // service checks on the same IP address.
114 // Note that currently, users of this don't actually care about the forced-bit.
115 // If they did, we'd probably want a more correct (and expensive) method of
116 // combining the state-bits, such that the output forced-bit is only copied if
117 // the forcing had an effect (e.g. forced-down + unforced-down = unforced-down)
118 F_PURE F_UNUSED
gdnsd_sttl_min2(const gdnsd_sttl_t a,const gdnsd_sttl_t b)119 static gdnsd_sttl_t gdnsd_sttl_min2(const gdnsd_sttl_t a, const gdnsd_sttl_t b) {
120 const gdnsd_sttl_t a_ttl = a & GDNSD_STTL_TTL_MASK;
121 const gdnsd_sttl_t b_ttl = b & GDNSD_STTL_TTL_MASK;
122 const gdnsd_sttl_t state = (a | b) & (GDNSD_STTL_DOWN | GDNSD_STTL_FORCED);
123 return (a_ttl < b_ttl) ? (state | a_ttl) : (state | b_ttl);
124 }
125
126 // As above, but generalized to an array of table indices to support merging
127 // several different service_type checks against a single IP for
128 // a single resource.
129 F_NONNULLX(1) F_PURE F_UNUSED
gdnsd_sttl_min(const gdnsd_sttl_t * sttl_tbl,const unsigned * idx_ary,const unsigned idx_ary_len)130 static gdnsd_sttl_t gdnsd_sttl_min(const gdnsd_sttl_t* sttl_tbl, const unsigned* idx_ary, const unsigned idx_ary_len) {
131 gdnsd_sttl_t rv = GDNSD_STTL_TTL_MAX;
132 for(unsigned i = 0; i < idx_ary_len; i++)
133 rv = gdnsd_sttl_min2(rv, sttl_tbl[idx_ary[i]]);
134 return rv;
135 }
136
137 #endif // GDNSD_MON_H
138