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