Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #ifndef SRC_VNSW_AGENT_SERVICES_HEALTH_CHECK_H_
7 : #define SRC_VNSW_AGENT_SERVICES_HEALTH_CHECK_H_
8 :
9 : #include <boost/scoped_ptr.hpp>
10 : #include <cmn/agent.h>
11 : #include <oper_db.h>
12 :
13 : extern SandeshTraceBufferPtr HealthCheckTraceBuf;
14 : #define HEALTH_CHECK_TRACE(obj, ...)\
15 : do {\
16 : HealthCheck##obj::TraceMsg(HealthCheckTraceBuf, __FILE__, __LINE__,\
17 : __VA_ARGS__);\
18 : } while (false)
19 :
20 : class Interface;
21 : class HealthCheckTable;
22 : class HealthCheckService;
23 : class MetaDataIp;
24 : class MetaDataIpAllocator;
25 : class InstanceTask;
26 : class InstanceTaskExecvp;
27 :
28 : ///////////////////////////////////////////////////////////////////////////////
29 : // HealthCheck module provides service to monitor status of given service
30 : // on an interface and updates the interface state accordingly to propagate
31 : // information accordingly
32 : ///////////////////////////////////////////////////////////////////////////////
33 :
34 : struct HealthCheckServiceKey : public AgentOperDBKey {
35 0 : HealthCheckServiceKey(const boost::uuids::uuid &id) :
36 0 : AgentOperDBKey(), uuid_(id) { }
37 0 : HealthCheckServiceKey(const boost::uuids::uuid &id, DBSubOperation sub_op) :
38 0 : AgentOperDBKey(sub_op), uuid_(id) { }
39 0 : virtual ~HealthCheckServiceKey() { }
40 :
41 : boost::uuids::uuid uuid_;
42 : };
43 :
44 : struct HealthCheckServiceData : public AgentOperDBData {
45 0 : HealthCheckServiceData(Agent *agent, IpAddress dest_ip,
46 : const std::string &name,
47 : const std::string &monitor_type,
48 : const std::string &stype,
49 : uint8_t ip_proto,
50 : const std::string &http_method,
51 : const std::string &url_path,
52 : uint16_t url_port,
53 : const std::string &expected_codes,
54 : uint32_t delay, uint64_t delay_usecs,
55 : uint32_t timeout, uint64_t timeout_usecs,
56 : uint32_t max_retries,
57 : bool is_all_ip,
58 : std::set<IpAddress> cfg_target_ip_list,
59 0 : IFMapNode *ifmap_node) :
60 0 : AgentOperDBData(agent, ifmap_node), dest_ip_(dest_ip), name_(name),
61 0 : monitor_type_(monitor_type), service_type_(stype), ip_proto_(ip_proto),
62 0 : http_method_(http_method), url_path_(url_path), url_port_(url_port),
63 0 : expected_codes_(expected_codes), delay_(delay),
64 0 : delay_usecs_(delay_usecs), timeout_(timeout),
65 0 : timeout_usecs_(timeout_usecs), max_retries_(max_retries),
66 0 : is_all_ip_(is_all_ip),
67 0 : new_target_ip_list_(cfg_target_ip_list) {
68 0 : }
69 0 : virtual ~HealthCheckServiceData() {}
70 :
71 : IpAddress dest_ip_;
72 : std::string name_;
73 : std::string monitor_type_;
74 : // Service type of HealthCheck segment/end-to-end/link-local
75 : std::string service_type_;
76 : uint8_t ip_proto_;
77 : std::string http_method_;
78 : std::string url_path_;
79 : uint16_t url_port_;
80 : std::string expected_codes_;
81 : uint32_t delay_;
82 : uint64_t delay_usecs_;
83 : uint32_t timeout_;
84 : uint64_t timeout_usecs_;
85 : uint32_t max_retries_;
86 : std::set<boost::uuids::uuid> intf_uuid_list_;
87 : std::set<boost::uuids::uuid> vn_uuid_list_;
88 : bool is_all_ip_;
89 : std::set<IpAddress> new_target_ip_list_;
90 : };
91 :
92 : struct HealthCheckInstanceEvent {
93 : public:
94 : enum EventType {
95 : MESSAGE_READ = 0,
96 : TASK_EXIT,
97 : SET_SERVICE,
98 : STOP_TASK,
99 : EVENT_MAXIMUM
100 : };
101 :
102 : HealthCheckInstanceEvent(HealthCheckInstanceBase *inst,
103 : HealthCheckService *service, EventType type,
104 : const std::string &message);
105 : virtual ~HealthCheckInstanceEvent();
106 :
107 : HealthCheckInstanceBase *instance_;
108 : HealthCheckService *service_;
109 : EventType type_;
110 : std::string message_;
111 : DISALLOW_COPY_AND_ASSIGN(HealthCheckInstanceEvent);
112 : };
113 :
114 : class HealthCheckInstanceBase {
115 : public:
116 :
117 : HealthCheckInstanceBase(HealthCheckService *service,
118 : MetaDataIpAllocator *allocator,
119 : VmInterface *intf,
120 : bool ignore_status_event);
121 : virtual ~HealthCheckInstanceBase();
122 :
123 : virtual bool CreateInstanceTask() = 0;
124 :
125 : // return true it instance is scheduled to destroy
126 : // when API returns false caller need to assure delete of
127 : // Health Check Instance
128 : virtual bool DestroyInstanceTask() = 0;
129 : virtual bool RunInstanceTask() = 0;
130 : virtual bool StopInstanceTask() = 0;
131 0 : virtual bool UpdateInstanceTask() { return true; }
132 :
133 : // OnRead Callback for Task
134 : void OnRead(const std::string &data);
135 : // OnExit Callback for Task
136 : void OnExit(const boost::system::error_code &ec);
137 : // Callback to enqueue set service
138 : void SetService(HealthCheckService *service);
139 : // Callback to enqueue stop task
140 : void StopTask(HealthCheckService *service);
141 :
142 : virtual void ResyncTarget(const HealthCheckService *service) const;
143 : void set_service(HealthCheckService *service);
144 : std::string to_string();
145 0 : bool active() {return active_;}
146 0 : virtual bool IsRunning() const { return true; }
147 0 : HealthCheckService *service() const { return service_.get(); }
148 0 : InterfaceRef interface() const { return intf_; }
149 0 : MetaDataIp *ip() const { return ip_.get(); }
150 0 : const std::string &last_update_time() const { return last_update_time_; }
151 0 : bool IsStatusEventIgnored() const { return ignore_status_event_; }
152 0 : void set_source_ip(const IpAddress &ip) { source_ip_ = ip; }
153 0 : IpAddress get_source_ip() const { return source_ip_; };
154 : IpAddress source_ip() const;
155 : IpAddress update_source_ip();
156 : void set_destination_ip(const IpAddress &ip);
157 : IpAddress destination_ip() const;
158 : void EnqueueHealthCheckResync(const HealthCheckService *service,
159 : const VmInterface *itf) const;
160 :
161 : protected:
162 : void EnqueueResync(const HealthCheckService *service, Interface *itf) const;
163 : friend class HealthCheckTable;
164 : // reference to health check service under
165 : // which this instance is running
166 : HealthCheckServiceRef service_;
167 : // Interface associated to this HealthCheck Instance
168 : InterfaceRef intf_;
169 : // MetaData IP Created for this HealthCheck Instance
170 : boost::scoped_ptr<MetaDataIp> ip_;
171 : // current status of HealthCheckInstance
172 : bool active_;
173 : // last update time
174 : std::string last_update_time_;
175 : // instance is delete marked
176 : bool deleted_;
177 : // true if the health check up or down status event has to be ignored
178 : bool ignore_status_event_;
179 :
180 : // source IP to be used while doing the health check
181 : IpAddress source_ip_;
182 : // destination IP for the health check
183 : IpAddress destination_ip_;
184 :
185 : private:
186 : DISALLOW_COPY_AND_ASSIGN(HealthCheckInstanceBase);
187 : };
188 :
189 : // Health check instance using the instance task infrastructure
190 : class HealthCheckInstanceTask : public HealthCheckInstanceBase {
191 : public:
192 : typedef InstanceTaskExecvp HeathCheckProcessInstance;
193 : static const std::string kHealthCheckCmd;
194 :
195 : HealthCheckInstanceTask(HealthCheckService *service,
196 : MetaDataIpAllocator *allocator, VmInterface *intf,
197 : bool ignore_status_event);
198 : virtual ~HealthCheckInstanceTask();
199 :
200 : virtual bool CreateInstanceTask();
201 : virtual bool DestroyInstanceTask();
202 : virtual bool RunInstanceTask();
203 : virtual bool StopInstanceTask();
204 : virtual bool IsRunning() const;
205 :
206 : private:
207 : friend class HealthCheckTable;
208 :
209 : void UpdateInstanceTaskCommand();
210 :
211 : // task managing external running script for status
212 : boost::scoped_ptr<HeathCheckProcessInstance> task_;
213 :
214 : DISALLOW_COPY_AND_ASSIGN(HealthCheckInstanceTask);
215 : };
216 :
217 : // Health check instance using the services infrastructure
218 : class HealthCheckInstanceService : public HealthCheckInstanceBase {
219 : public:
220 : HealthCheckInstanceService(HealthCheckService *service,
221 : MetaDataIpAllocator *allocator,
222 : VmInterface *intf, VmInterface *other_intf,
223 : bool ignore_status_event, bool multi_hop);
224 : virtual ~HealthCheckInstanceService();
225 :
226 : virtual bool CreateInstanceTask();
227 : virtual bool DestroyInstanceTask();
228 : virtual bool RunInstanceTask();
229 : virtual bool StopInstanceTask();
230 : virtual bool UpdateInstanceTask();
231 : virtual void ResyncTarget(const HealthCheckService *service) const;
232 : void EnqueueMacIpLearningHCStatus(const HealthCheckService *service) const;
233 :
234 : typedef boost::function<void()> BfdDownCallback;
235 0 : void SetBfdDownCallback(const BfdDownCallback &callback) {
236 0 : bfd_down_callback_ = callback;
237 0 : }
238 : void BfdStateChange(bool up);
239 :
240 0 : bool is_multi_hop() const { return multi_hop_; }
241 :
242 : private:
243 : friend class HealthCheckTable;
244 :
245 : // Other Interface associated to this HealthCheck Instance when
246 : // HealthCheck service type is "segment"
247 : InterfaceRef other_intf_;
248 :
249 : // BFD health check can be single hop or multi hop, when started for a
250 : // BGP flow, make it multi hop
251 : bool multi_hop_;
252 :
253 : // True only after BFD has reached Up at least once. This prevents the
254 : // initial Down notification from deleting a newly-created BGP flow.
255 : bool bfd_up_;
256 : BfdDownCallback bfd_down_callback_;
257 :
258 : DISALLOW_COPY_AND_ASSIGN(HealthCheckInstanceService);
259 : };
260 :
261 : class HealthCheckMacIpInstanceService : public HealthCheckInstanceService {
262 : public:
263 : HealthCheckMacIpInstanceService(HealthCheckService *service,
264 : MetaDataIpAllocator *allocator,
265 : VmInterface *intf, VmInterface *other_intf,
266 : bool ignore_status_event, bool multi_hop);
267 : virtual ~HealthCheckMacIpInstanceService();
268 :
269 : virtual void ResyncTarget(const HealthCheckService *service) const;
270 0 : virtual void set_destination_mac(const MacAddress &mac) {
271 0 : mac_ = mac;
272 0 : }
273 0 : virtual const MacAddress destination_mac() const { return mac_; }
274 :
275 : private:
276 : friend class HealthCheckTable;
277 :
278 : MacAddress mac_;
279 :
280 : DISALLOW_COPY_AND_ASSIGN(HealthCheckMacIpInstanceService);
281 : };
282 :
283 : class HealthCheckService : AgentRefCount<HealthCheckService>,
284 : public AgentOperDBEntry {
285 : public:
286 : enum HealthCheckType {
287 : PING,
288 : HTTP,
289 : BFD,
290 : SEGMENT,
291 : MAX_HEALTH_CHECK_SERVICES
292 : };
293 : typedef std::map<boost::uuids::uuid, HealthCheckInstanceBase *> InstanceList;
294 : typedef std::map<IpAddress, HealthCheckInstanceBase *> IpInstanceList;
295 :
296 : HealthCheckService(const HealthCheckTable *table,
297 : const boost::uuids::uuid &id);
298 : ~HealthCheckService();
299 :
300 : virtual bool IsLess(const DBEntry &rhs) const;
301 : virtual std::string ToString() const;
302 : virtual KeyPtr GetDBRequestKey() const;
303 : virtual void SetKey(const DBRequestKey *key);
304 0 : uint32_t GetRefCount() const {
305 0 : return AgentRefCount<HealthCheckService>::GetRefCount();
306 : }
307 :
308 : bool DBEntrySandesh(Sandesh *resp, std::string &name) const;
309 :
310 : void PostAdd();
311 : bool Copy(HealthCheckTable *table, const HealthCheckServiceData *data);
312 :
313 : HealthCheckInstanceBase *StartHealthCheckService(VmInterface *intrface,
314 : VmInterface *paired_vmi,
315 : const IpAddress &source_ip,
316 : const IpAddress &destination_ip,
317 : const MacAddress &destination_mac,
318 : bool ignore_status_event,
319 : bool multi_hop);
320 0 : HealthCheckInstanceBase *StartHealthCheckService(
321 : VmInterface *intrface, const IpAddress &source_ip,
322 : const IpAddress &destination_ip,
323 : const MacAddress destination_mac = MacAddress()) {
324 : // health check status event is ignored
325 0 : return StartHealthCheckService(intrface, NULL, source_ip,
326 : destination_ip, destination_mac,
327 0 : true, true);
328 : }
329 : void StopHealthCheckService(HealthCheckInstanceBase *instance);
330 :
331 : void UpdateInstanceServiceReference();
332 : void ResyncHealthCheckInterface(const HealthCheckService *service,
333 : const VmInterface *intf);
334 : void UpdateInterfaceInstanceServiceReference(const VmInterface *intf);
335 : void DeleteInstances();
336 :
337 0 : const boost::uuids::uuid &uuid() const { return uuid_; }
338 0 : const std::string &name() const { return name_; }
339 :
340 : uint8_t ip_proto() const { return ip_proto_; }
341 2 : uint16_t url_port() const { return url_port_; }
342 0 : uint32_t delay() const { return delay_; }
343 0 : uint64_t delay_usecs() const { return delay_usecs_; }
344 0 : uint32_t timeout() const { return timeout_; }
345 0 : uint64_t timeout_usecs() const { return timeout_usecs_; }
346 0 : uint32_t max_retries() const { return max_retries_; }
347 0 : const std::string &url_path() const { return url_path_; }
348 0 : const std::string &monitor_type() const { return monitor_type_; }
349 0 : const HealthCheckTable *table() const { return table_; }
350 : bool IsInstanceTaskBased() const;
351 : bool IsSegmentHealthCheckService() const;
352 : bool IsVnIpListHealthCheckService() const;
353 0 : HealthCheckType health_check_type() const {
354 0 : return health_check_type_;
355 : }
356 0 : const std::set<boost::uuids::uuid> &GetVnUuidList() {
357 0 : return vn_uuid_list_;
358 : }
359 0 : const std::set<IpAddress> &GetTargetIpList() {
360 0 : return target_ip_list_;
361 : }
362 0 : bool IsTargetIpPresent(IpAddress &ip) {
363 :
364 0 : if (is_hc_enable_all_ip_ ||
365 0 : target_ip_list_.find(ip) != target_ip_list_.end()) {
366 0 : return true;
367 : }
368 0 : return false;
369 : }
370 1 : IpAddress dest_ip() const { return dest_ip_;}
371 0 : bool IsHcEnableAllTargetIp() const {return is_hc_enable_all_ip_;}
372 :
373 : private:
374 : friend struct HealthCheckInstanceEvent;
375 :
376 : HealthCheckType GetHealthCheckType() const;
377 :
378 : const HealthCheckTable *table_;
379 : boost::uuids::uuid uuid_;
380 : IpAddress dest_ip_;
381 : std::string name_;
382 : // monitor type of service PING/HTTP/BFD etc
383 : std::string monitor_type_;
384 : // Service type of HealthCheck segment/end-to-end/link-local
385 : std::string service_type_;
386 : // ip_proto derived from monitor_type_
387 : uint8_t ip_proto_;
388 : std::string http_method_;
389 : std::string url_path_;
390 : // tcp/udp port numbers derived from url
391 : uint16_t url_port_;
392 : std::string expected_codes_;
393 : uint32_t delay_;
394 : uint64_t delay_usecs_;
395 : uint32_t timeout_;
396 : uint64_t timeout_usecs_;
397 : uint32_t max_retries_;
398 : // List of interfaces associated to this HealthCheck Service
399 : InstanceList intf_list_;
400 : HealthCheckType health_check_type_;
401 :
402 : std::set<boost::uuids::uuid> vn_uuid_list_;
403 : std::set<IpAddress> target_ip_list_;
404 : bool is_hc_enable_all_ip_;
405 :
406 : DISALLOW_COPY_AND_ASSIGN(HealthCheckService);
407 : };
408 :
409 : class HealthCheckTable : public AgentOperDBTable {
410 : public:
411 : enum HealthCheckServiceAction {
412 : CREATE_SERVICE,
413 : DELETE_SERVICE,
414 : RUN_SERVICE,
415 : STOP_SERVICE,
416 : UPDATE_SERVICE
417 : };
418 : typedef boost::function<bool(HealthCheckServiceAction,
419 : HealthCheckInstanceService *)>
420 : HealthCheckServiceCallback;
421 :
422 : typedef boost::function<void(const HealthCheckInstanceService *)>
423 : HealthCheckNotifyCallback;
424 :
425 : HealthCheckTable(Agent *agent, DB *db, const std::string &name);
426 : virtual ~HealthCheckTable();
427 :
428 : static DBTableBase *CreateTable(Agent *agent, DB *db,
429 : const std::string &name);
430 :
431 : virtual std::unique_ptr<DBEntry> AllocEntry(const DBRequestKey *k) const;
432 0 : virtual size_t Hash(const DBEntry *entry) const {return 0;}
433 0 : virtual size_t Hash(const DBRequestKey *key) const {return 0;}
434 :
435 : virtual DBEntry *OperDBAdd(const DBRequest *req);
436 : virtual bool OperDBOnChange(DBEntry *entry, const DBRequest *req);
437 : virtual bool OperDBResync(DBEntry *entry, const DBRequest *req);
438 : virtual bool OperDBDelete(DBEntry *entry, const DBRequest *req);
439 :
440 : virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req,
441 : const boost::uuids::uuid &u);
442 : bool ProcessConfig(IFMapNode *node, DBRequest &req,
443 : const boost::uuids::uuid &u);
444 : virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u);
445 : virtual AgentSandeshPtr GetAgentSandesh(const AgentSandeshArguments *args,
446 : const std::string &context);
447 :
448 : HealthCheckService *Find(const boost::uuids::uuid &u);
449 :
450 : void InstanceEventEnqueue(HealthCheckInstanceEvent *event) const;
451 : bool InstanceEventProcess(HealthCheckInstanceEvent *event);
452 :
453 4 : void RegisterHealthCheckCallback(HealthCheckServiceCallback fn,
454 : HealthCheckService::HealthCheckType type) {
455 4 : health_check_service_cb_[type] = fn;
456 4 : }
457 0 : HealthCheckServiceCallback health_check_service_callback(
458 : HealthCheckService::HealthCheckType type) const {
459 0 : return health_check_service_cb_[type];
460 : }
461 2 : void RegisterHealthCheckNotifyCallback(HealthCheckNotifyCallback fn) {
462 2 : health_check_notify_cb_ = fn;
463 2 : }
464 0 : HealthCheckNotifyCallback health_check_notify_callback() const {
465 0 : return health_check_notify_cb_;
466 : }
467 :
468 : private:
469 :
470 : WorkQueue<HealthCheckInstanceEvent *> *inst_event_queue_;
471 : HealthCheckServiceCallback health_check_service_cb_[HealthCheckService::MAX_HEALTH_CHECK_SERVICES];
472 : HealthCheckNotifyCallback health_check_notify_cb_;
473 : DISALLOW_COPY_AND_ASSIGN(HealthCheckTable);
474 : };
475 :
476 : struct HealthCheckResyncInterfaceData : public AgentOperDBData {
477 0 : HealthCheckResyncInterfaceData(const Agent *agent, IFMapNode *node,
478 0 : const VmInterface *intf):
479 0 : AgentOperDBData(agent, node), intf_(intf) {}
480 : const VmInterface *intf_;
481 : };
482 :
483 : #endif // SRC_VNSW_AGENT_SERVICES_HEALTH_CHECK_H_
|