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