Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <stdint.h>
7 : #include "base/os.h"
8 : #include <map>
9 : #include "vr_defs.h"
10 : #include "base/timer.h"
11 : #include "cmn/agent_cmn.h"
12 : #include "pkt/proto.h"
13 : #include "pkt/proto_handler.h"
14 : #include "diag/diag.h"
15 : #include "diag/diag_proto.h"
16 : #include "diag/ping.h"
17 : #include "oper/mirror_table.h"
18 : #include "diag/diag_pkt_handler.h"
19 :
20 :
21 : const std::string KDiagName("DiagTimeoutHandler");
22 : const std::string DiagTable::kDiagData = "diagshc";
23 : using namespace boost::posix_time;
24 : ////////////////////////////////////////////////////////////////////////////////
25 :
26 0 : DiagEntry::DiagEntry(const std::string &sip, const std::string &dip,
27 : uint8_t proto, uint16_t sport, uint16_t dport,
28 : const std::string &vrf_name, int timeout,
29 0 : int attempts, DiagTable *diag_table) :
30 0 : sip_(IpAddress::from_string(sip, ec_)),
31 0 : dip_(IpAddress::from_string(dip, ec_)),
32 0 : proto_(proto), sport_(sport), dport_(dport),
33 0 : vrf_name_(vrf_name), diag_table_(diag_table), timeout_(timeout),
34 0 : timer_(TimerManager::CreateTimer(*(diag_table->agent()->event_manager())->io_service(),
35 : "DiagTimeoutHandler",
36 : TaskScheduler::GetInstance()->GetTaskId("Agent::Diag"),
37 : PktHandler::DIAG)),
38 0 : max_attempts_(attempts), seq_no_(0) {
39 0 : }
40 :
41 0 : DiagEntry::~DiagEntry() {
42 0 : timer_->Cancel();
43 0 : TimerManager::DeleteTimer(timer_);
44 : //Delete entry in DiagTable
45 0 : diag_table_->Delete(this);
46 0 : }
47 :
48 0 : void DiagEntry::Init() {
49 0 : DiagEntryOp *entry_op = new DiagEntryOp(DiagEntryOp::ADD, this);
50 0 : diag_table_->Enqueue(entry_op);
51 0 : }
52 :
53 0 : void DiagEntry::EnqueueForceDelete() {
54 0 : DiagEntryOp *entry_op = new DiagEntryOp(DiagEntryOp::FORCE_DELETE, this);
55 0 : diag_table_->Enqueue(entry_op);
56 0 : }
57 :
58 0 : void DiagEntry::RestartTimer() {
59 : //Cancel timer of running
60 0 : timer_->Cancel();
61 0 : timer_->Start(timeout_, boost::bind(&DiagEntry::TimerExpiry, this, seq_no_));
62 0 : }
63 :
64 0 : bool DiagEntry::IsDone() {
65 0 : return (GetSeqNo() == GetMaxAttempts()) ? true : false;
66 : }
67 :
68 0 : bool DiagEntry::TimerExpiry( uint32_t seq_no) {
69 : DiagEntryOp *op;
70 0 : RequestTimedOut(seq_no);
71 0 : if (IsDone()) {
72 0 : op = new DiagEntryOp(DiagEntryOp::DEL, this);
73 0 : diag_table_->Enqueue(op);
74 0 : return false;
75 : }
76 :
77 0 : if (ResendOnTimerExpiry()) {
78 0 : SendRequest();
79 0 : return true;
80 : }
81 :
82 0 : return false;
83 : }
84 :
85 0 : void DiagEntry::Retry() {
86 0 : SendRequest();
87 0 : RestartTimer();
88 0 : }
89 :
90 0 : bool DiagTable::Process(DiagEntryOp *op) {
91 0 : switch (op->op_) {
92 0 : case DiagEntryOp::ADD:
93 0 : Add(op->de_);
94 0 : break;
95 :
96 0 : case DiagEntryOp::DEL:
97 0 : if (op->de_->TimerCancel() == true) {
98 0 : op->de_->SendSummary();
99 0 : delete op->de_;
100 : }
101 0 : break;
102 :
103 0 : case DiagEntryOp::FORCE_DELETE:
104 0 : op->de_->TimerCancel();
105 0 : delete op->de_;
106 0 : break;
107 :
108 0 : case DiagEntryOp::RETRY:
109 0 : op->de_->Retry();
110 0 : break;
111 : }
112 :
113 0 : delete op;
114 0 : return true;
115 : }
116 :
117 2 : DiagTable::DiagTable(Agent *agent):agent_(agent) {
118 2 : diag_proto_.reset(
119 2 : new DiagProto(agent, *(agent->event_manager())->io_service()));
120 4 : entry_op_queue_ = new WorkQueue<DiagEntryOp *>
121 4 : (TaskScheduler::GetInstance()->GetTaskId("Agent::Diag"),
122 : PktHandler::DIAG,
123 2 : boost::bind(&DiagTable::Process, this, _1));
124 2 : entry_op_queue_->set_name("Diagnostics Table");
125 2 : index_ = 1;
126 2 : }
127 :
128 2 : void DiagTable::Shutdown() {
129 2 : entry_op_queue_->Shutdown();
130 2 : delete entry_op_queue_;
131 2 : diag_proto_.reset(NULL);
132 2 : }
133 :
134 2 : DiagTable::~DiagTable() {
135 2 : assert(tree_.size() == 0);
136 2 : }
137 :
138 0 : void DiagTable::Add(DiagEntry *de) {
139 0 : de->SetKey(index_++);
140 0 : tree_.insert(std::make_pair(de->GetKey(), de));
141 0 : de->SendRequest();
142 0 : de->RestartTimer();
143 0 : }
144 :
145 0 : void DiagTable::Delete(DiagEntry *de) {
146 0 : tree_.erase(de->GetKey());
147 0 : }
148 :
149 0 : DiagEntry* DiagTable::Find(DiagEntry::DiagKey &key) {
150 0 : DiagEntryTree::const_iterator it;
151 :
152 0 : it = tree_.find(key);
153 0 : if (it == tree_.end()) {
154 0 : return NULL;
155 : }
156 :
157 0 : return static_cast<DiagEntry *>(it->second);
158 : }
159 :
160 0 : void DiagTable::Enqueue(DiagEntryOp *op) {
161 0 : entry_op_queue_->Enqueue(op);
162 0 : }
163 :
164 0 : uint32_t DiagEntry::HashValUdpSourcePort() {
165 0 : std::size_t seed = 0;
166 0 : boost::hash_combine(seed, sip_.to_v4().to_ulong());
167 0 : boost::hash_combine(seed, dip_.to_v4().to_ulong());
168 0 : boost::hash_combine(seed, proto_);
169 0 : boost::hash_combine(seed, sport_);
170 0 : boost::hash_combine(seed, dport_);
171 0 : return seed;
172 : }
173 :
174 0 : void DiagEntry::FillOamPktHeader(OverlayOamPktData *pktdata, uint32_t vxlan_id,
175 : const boost::posix_time::ptime &time) {
176 0 : pktdata->msg_type_ = AgentDiagPktData::DIAG_REQUEST;
177 0 : pktdata->reply_mode_ = OverlayOamPktData::REPLY_OVERLAY_SEGMENT;
178 0 : pktdata->org_handle_ = htons(key_);
179 0 : pktdata->seq_no_ = htonl(seq_no_);
180 :
181 : boost::posix_time::ptime
182 0 : epoch(boost::gregorian::date(1970, boost::gregorian::Jan, 1));
183 0 : boost::posix_time::time_duration td = time - epoch;
184 0 : pktdata->timesent_sec_ = htonl(td.total_seconds());
185 0 : pktdata->timesent_misec_ = htonl(td.total_microseconds());
186 :
187 0 : if (sip_.is_v4()) {
188 0 : pktdata->oamtlv_.type_ = htons(OamTlv::VXLAN_PING_IPv4);
189 0 : pktdata->oamtlv_.length_ = htons(sizeof(OamTlv::VxlanOamV4Tlv));
190 0 : OamTlv::VxlanOamV4Tlv *vxlan_tlv =
191 : (OamTlv::VxlanOamV4Tlv *) pktdata->oamtlv_.data_;
192 0 : vxlan_tlv->vxlan_id_ = htonl(vxlan_id);
193 0 : vxlan_tlv->sip_ = htonl(sip_.to_v4().to_ulong());
194 : } else {
195 0 : pktdata->oamtlv_.type_ = htons(OamTlv::VXLAN_PING_IPv6);
196 0 : pktdata->oamtlv_.length_ = htons(sizeof(OamTlv::VxlanOamV6Tlv));
197 0 : OamTlv::VxlanOamV6Tlv *vxlan_tlv =
198 : (OamTlv::VxlanOamV6Tlv *) pktdata->oamtlv_.data_;
199 0 : vxlan_tlv->vxlan_id_ = htonl(vxlan_id);
200 0 : memcpy(vxlan_tlv->sip_, sip_.to_v6().to_bytes().data(), 16);
201 : }
202 0 : }
|