Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <boost/uuid/uuid_io.hpp>
6 : #include <cmn/agent_cmn.h>
7 : #include <init/agent_param.h>
8 : #include <base/task_annotations.h>
9 : #include <oper/interface_common.h>
10 : #include <oper/vrf.h>
11 : #include <oper/nexthop.h>
12 : #include <oper/mpls.h>
13 : #include <oper/mirror_table.h>
14 : #include <oper/agent_sandesh.h>
15 : #include <resource_manager/resource_manager.h>
16 : #include <resource_manager/resource_table.h>
17 : #include <resource_manager/mpls_index.h>
18 :
19 : using namespace std;
20 :
21 : SandeshTraceBufferPtr MplsTraceBuf(SandeshTraceBufferCreate("MplsTrace", 1000));
22 :
23 : /****************************************************************************
24 : * MplsLabel routines
25 : ***************************************************************************/
26 14149 : MplsLabel::MplsLabel(Agent *agent, uint32_t label) :
27 14149 : agent_(agent), label_(label), free_label_(false) {
28 14149 : }
29 :
30 28298 : MplsLabel::~MplsLabel() {
31 14149 : if (free_label_) {
32 1530 : if (label_ != MplsTable::kInvalidLabel) {
33 1530 : MplsTable *table = static_cast<MplsTable *>(get_table());
34 1530 : table->FreeMplsLabelIndex(label_);
35 : }
36 1530 : agent_->resource_manager()->Release(Resource::MPLS_INDEX, label_);
37 : }
38 28298 : }
39 :
40 102271 : bool MplsLabel::IsLess(const DBEntry &rhs) const {
41 102271 : const MplsLabel &mpls = static_cast<const MplsLabel &>(rhs);
42 102271 : return label_ < mpls.label_;
43 : }
44 :
45 0 : std::string MplsLabel::ToString() const {
46 0 : return "MPLS";
47 : }
48 :
49 1387 : DBEntryBase::KeyPtr MplsLabel::GetDBRequestKey() const {
50 1387 : MplsLabelKey *key = new MplsLabelKey(label_);
51 1387 : return DBEntryBase::KeyPtr(key);
52 : }
53 :
54 0 : void MplsLabel::SetKey(const DBRequestKey *k) {
55 0 : const MplsLabelKey *key = static_cast<const MplsLabelKey *>(k);
56 0 : label_ = key->label();
57 0 : }
58 :
59 1530 : uint32_t MplsLabel::GetRefCount() const {
60 1530 : return AgentRefCount<MplsLabel>::GetRefCount();
61 : }
62 :
63 1530 : void MplsLabel::Add(const DBRequest *req) {
64 1530 : free_label_ = true;
65 1530 : ChangeInternal(req);
66 1530 : SendObjectLog(agent_->mpls_table(), AgentLogEvent::ADD);
67 1530 : return;
68 : }
69 :
70 2438 : bool MplsLabel::Change(const DBRequest *req) {
71 2438 : const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
72 2438 : bool ret = ChangeInternal(req);
73 2438 : SendObjectLog(table, AgentLogEvent::CHANGE);
74 2438 : return ret;
75 : }
76 :
77 1530 : void MplsLabel::Delete(const DBRequest *req) {
78 1530 : const AgentDBTable *table = static_cast<const AgentDBTable *>(get_table());
79 1530 : SendObjectLog(table, AgentLogEvent::DEL);
80 1530 : return;
81 : }
82 :
83 3968 : bool MplsLabel::ChangeInternal(const DBRequest *req) {
84 3968 : NextHopTable *nh_table = agent_->nexthop_table();
85 3968 : MplsLabelData *data = static_cast<MplsLabelData *>(req->data.get());
86 : NextHop *nh =
87 3968 : static_cast<NextHop *>(nh_table->FindActiveEntry(data->nh_key()));
88 3968 : if (!nh) {
89 : // NextHop not found, point mpls label to discard
90 54 : DiscardNH key;
91 54 : nh = static_cast<NextHop *>(nh_table->FindActiveEntry(&key));
92 54 : }
93 :
94 3968 : return ChangeNH(nh);
95 : }
96 :
97 6973 : bool MplsLabel::ChangeNH(NextHop *nh) {
98 6973 : if (nh_ == nh)
99 4780 : return false;
100 :
101 2193 : assert(nh);
102 2193 : nh_ = nh;
103 :
104 2193 : if (IsFabricMulticastReservedLabel()) {
105 0 : CompositeNH *cnh = dynamic_cast<CompositeNH*>(nh);
106 0 : if (cnh && cnh->vrf()) {
107 0 : FmgVrfNhMap::iterator it = fmg_nh_list_.begin();
108 0 : while( it != fmg_nh_list_.end()) {
109 0 : if (it->first != cnh->vrf()->GetName()) {
110 0 : FmgVrfNhMap::iterator temp_it;
111 0 : temp_it = it;
112 0 : it++;
113 0 : fmg_nh_list_.erase(temp_it);
114 : } else {
115 0 : it++;
116 : }
117 : }
118 0 : fmg_nh_list_[cnh->vrf()->GetName()] = nh;
119 : }
120 : }
121 :
122 2193 : SyncDependentPath();
123 2193 : return true;
124 : }
125 :
126 2193 : void MplsLabel::SyncDependentPath() {
127 2193 : MPLS_TRACE(MplsTrace, "Syncing routes for label ", label());
128 2343 : for (DependentPathList::iterator iter =
129 4536 : mpls_label_.begin(); iter != mpls_label_.end(); iter++) {
130 150 : AgentRoute *rt = iter.operator->();
131 150 : rt->EnqueueRouteResync();
132 : }
133 2193 : }
134 :
135 2201 : bool MplsLabel::IsFabricMulticastReservedLabel() const {
136 : //MplsTable *table = static_cast<MplsTable *>(get_table());
137 2201 : MplsTable *table = static_cast<MplsTable *>(agent_->mpls_table());
138 2201 : return table->IsFabricMulticastLabel(label_);
139 : }
140 :
141 : /****************************************************************************
142 : * MplsLabel Sandesh routines
143 : ***************************************************************************/
144 0 : bool MplsLabel::DBEntrySandesh(Sandesh *sresp, std::string &name) const {
145 0 : MplsResp *resp = static_cast<MplsResp *>(sresp);
146 :
147 0 : MplsSandeshData data;
148 0 : data.set_label(label_);
149 0 : nh_->SetNHSandeshData(data.nh);
150 : std::vector<MplsSandeshData> &list =
151 0 : const_cast<std::vector<MplsSandeshData>&>(resp->get_mpls_list());
152 0 : list.push_back(data);
153 :
154 0 : return true;
155 0 : }
156 :
157 5498 : void MplsLabel::SendObjectLog(const AgentDBTable *table,
158 : AgentLogEvent::type event) const {
159 5498 : MplsObjectLogInfo info;
160 5498 : string str, type_str, nh_type;
161 5498 : info.set_type(type_str);
162 5498 : info.set_label((int)label_);
163 5498 : switch (event) {
164 1530 : case AgentLogEvent::ADD:
165 1530 : str.assign("Addition ");
166 1530 : break;
167 1530 : case AgentLogEvent::DEL:
168 1530 : str.assign("Deletion ");
169 1530 : info.set_event(str);
170 1530 : OPER_TRACE_ENTRY(Mpls, table, info);
171 1530 : return;
172 2438 : case AgentLogEvent::CHANGE:
173 2438 : str.assign("Modification ");
174 2438 : break;
175 0 : default:
176 0 : str.assign("Unknown");
177 0 : break;
178 : }
179 3968 : info.set_event(str);
180 3968 : const NextHop *nh = nexthop();
181 3968 : const Interface *intf = NULL;
182 : /* Mpls is not expected to have any other nexthop apart from Interface
183 : or Vlan */
184 3968 : if (nh != NULL) {
185 3968 : string policy_str("Disabled");
186 : const InterfaceNH *if_nh;
187 : const VlanNH *vlan_nh;
188 :
189 3968 : switch(nh->GetType()) {
190 1296 : case NextHop::INTERFACE:
191 1296 : nh_type.assign("INTERFACE");
192 1296 : if_nh = static_cast<const InterfaceNH *>(nh);
193 1296 : intf = if_nh->GetInterface();
194 1296 : if (if_nh->PolicyEnabled()) {
195 522 : policy_str.assign("Enabled");
196 : }
197 1296 : info.set_policy(policy_str);
198 1296 : break;
199 4 : case NextHop::VLAN:
200 4 : nh_type.assign("VLAN");
201 4 : vlan_nh = static_cast<const VlanNH *>(nh);
202 4 : intf = vlan_nh->GetInterface();
203 4 : info.set_vlan_tag(vlan_nh->GetVlanTag());
204 4 : break;
205 2373 : case NextHop::COMPOSITE:
206 2373 : nh_type.assign("Composite");
207 2373 : break;
208 295 : default:
209 295 : nh_type.assign("unknown");
210 295 : break;
211 : }
212 3968 : }
213 3968 : info.set_nh_type(nh_type);
214 : /* Interface Nexthop pointed by Mpls object will always be of type VMPORT */
215 3968 : if (intf) {
216 1300 : string if_type_str;
217 1300 : switch(intf->type()) {
218 1300 : case Interface::VM_INTERFACE:
219 1300 : if_type_str.assign("VM_INTERFACE");
220 1300 : break;
221 0 : default:
222 0 : if_type_str.assign("Invalid");
223 0 : break;
224 : }
225 1300 : info.set_intf_type(if_type_str);
226 1300 : info.set_intf_uuid(UuidToString(intf->GetUuid()));
227 1300 : info.set_intf_name(intf->name());
228 1300 : }
229 3968 : OPER_TRACE_ENTRY(Mpls, table, info);
230 10088 : }
231 :
232 : /****************************************************************************
233 : * MplsTable routines
234 : ***************************************************************************/
235 4 : MplsTable::MplsTable(DB *db, const std::string &name) :
236 4 : AgentDBTable(db, name) {
237 4 : }
238 :
239 8 : MplsTable::~MplsTable() {
240 8 : }
241 :
242 4 : DBTableBase *MplsTable::CreateTable(DB *db, const std::string &name) {
243 4 : MplsTable *table = new MplsTable(db, name);
244 4 : table->Init();
245 4 : return table;
246 : };
247 :
248 5494 : void MplsTable::Process(DBRequest &req) {
249 5494 : agent()->ConcurrencyCheck();
250 : DBTablePartition *tpart =
251 5494 : static_cast<DBTablePartition *>(GetTablePartition(req.key.get()));
252 5494 : tpart->Process(NULL, &req);
253 5494 : }
254 :
255 : /*
256 : * Allocates label from resource manager, currently used for evpn and
257 : * ecmp labels.
258 : */
259 0 : uint32_t MplsTable::AllocLabel(ResourceManager::KeyPtr key) {
260 : uint32_t label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
261 0 : Allocate(key).get()))->index());
262 0 : assert(label != MplsTable::kInvalidLabel);
263 0 : return label;
264 : }
265 :
266 : //Free label from resource manager and delete db entry
267 57 : void MplsTable::FreeLabel(uint32_t label) {
268 57 : FreeLabel(label, std::string());
269 57 : }
270 :
271 143 : void MplsTable::FreeLabel(uint32_t label, const std::string &vrf_name) {
272 143 : DBRequest req;
273 143 : req.oper = DBRequest::DB_ENTRY_DELETE;
274 :
275 143 : MplsLabelKey *key = new MplsLabelKey(label);
276 143 : MplsLabelData *data = new MplsLabelData(NULL);
277 143 : data->set_vrf_name(vrf_name);
278 143 : req.key.reset(key);
279 143 : req.data.reset(data);
280 :
281 143 : Process(req);
282 143 : }
283 :
284 12619 : std::unique_ptr<DBEntry> MplsTable::AllocEntry(const DBRequestKey *k) const {
285 12619 : const MplsLabelKey *key = static_cast<const MplsLabelKey *>(k);
286 12619 : MplsLabel *mpls = new MplsLabel(agent(), key->label());
287 12619 : return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(mpls));
288 : }
289 :
290 1530 : DBEntry *MplsTable::Add(const DBRequest *req) {
291 1530 : CheckVrLabelLimit();
292 1530 : MplsLabelKey *key = static_cast<MplsLabelKey *>(req->key.get());
293 1530 : assert(key->label() != MplsTable::kInvalidLabel);
294 :
295 1530 : MplsLabel *mpls = new MplsLabel(agent(), key->label());
296 1530 : label_table_.InsertAtIndex(mpls->label(), mpls);
297 1530 : mpls->Add(req);
298 1530 : return mpls;
299 : }
300 :
301 2438 : bool MplsTable::OnChange(DBEntry *entry, const DBRequest *req) {
302 2438 : MplsLabel *mpls = static_cast<MplsLabel *>(entry);
303 2438 : return mpls->Change(req);
304 : }
305 :
306 1530 : bool MplsTable::Delete(DBEntry *entry, const DBRequest *req) {
307 1530 : MplsLabel *mpls = static_cast<MplsLabel *>(entry);
308 1530 : if (IsFabricMulticastLabel(mpls->label())) {
309 0 : MplsLabelData *data = static_cast<MplsLabelData *>(req->data.get());
310 : // For multicast labels we not expect to be here
311 : // via MplsTable::OnZeroRefcount where data is not set.
312 0 : assert(data);
313 0 : if (mpls->fmg_nh_list().find(data->vrf_name()) !=
314 0 : mpls->fmg_nh_list().end()) {
315 0 : mpls->fmg_nh_list().erase(data->vrf_name());
316 : }
317 0 : if (mpls->fmg_nh_list().empty() == false) {
318 0 : if (mpls->ChangeNH(mpls->fmg_nh_list().begin()->second.get())) {
319 : DBTablePartBase *tpart =
320 0 : static_cast<DBTablePartition *>(GetTablePartition(mpls));
321 0 : tpart->Notify(mpls);
322 : }
323 0 : return false;
324 : }
325 : }
326 1530 : mpls->Delete(req);
327 1530 : CheckVrLabelLimit();
328 1530 : return true;
329 : }
330 :
331 1387 : void MplsTable::OnZeroRefcount(AgentDBEntry *e) {
332 1387 : agent()->ConcurrencyCheck();
333 :
334 : //Delete db entry
335 1387 : DBRequest req(DBRequest::DB_ENTRY_DELETE);
336 1387 : req.key = e->GetDBRequestKey();
337 1387 : req.data.reset(NULL);
338 1387 : Process(req);
339 1387 : }
340 :
341 2577 : uint32_t MplsTable::CreateRouteLabel(uint32_t label, const NextHopKey *nh_key,
342 : const std::string &vrf_name,
343 : const std::string &route) {
344 2577 : if (label == MplsTable::kInvalidLabel) {
345 : ResourceManager::KeyPtr key(new RouteMplsResourceKey(agent()->
346 141 : resource_manager(), vrf_name,
347 141 : route));
348 : label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
349 141 : Allocate(key).get()))->index());
350 141 : assert(label != MplsTable::kInvalidLabel);
351 141 : assert(FindMplsLabel(label) == NULL);
352 141 : }
353 :
354 2577 : DBRequest req;
355 2577 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
356 :
357 2577 : MplsLabelKey *key = new MplsLabelKey(label);
358 2577 : req.key.reset(key);
359 :
360 2577 : MplsLabelData *data = new MplsLabelData(nh_key->Clone());
361 2577 : data->set_vrf_name(vrf_name);
362 2577 : req.data.reset(data);
363 :
364 2577 : Process(req);
365 2577 : return label;
366 2577 : }
367 :
368 5570 : bool MplsTable::IsFabricMulticastLabel(uint32_t label) const {
369 16710 : for (uint8_t count = 0; count < MAX_XMPP_SERVERS; count++) {
370 11140 : if ((label >= multicast_label_start_[count]) &&
371 40 : (label <= multicast_label_end_[count])) return true;
372 : }
373 5570 : return false;
374 : }
375 :
376 12 : void MplsTable::ReserveLabel(uint32_t start, uint32_t end) {
377 : // We want to allocate labels from an offset
378 : // Pre-allocate entries
379 76 : for (uint32_t i = start; i <= end; i++) {
380 64 : agent()->resource_manager()->ReserveIndex(Resource::MPLS_INDEX, i);
381 : }
382 12 : }
383 :
384 4 : void MplsTable::FreeReserveLabel(uint32_t start, uint32_t end) {
385 : // We want to allocate labels from an offset
386 : // Pre-allocate entries
387 68 : for (uint32_t i = start; i <= end; i++) {
388 64 : agent()->resource_manager()->ReleaseIndex(Resource::MPLS_INDEX, i);
389 : }
390 4 : }
391 :
392 8 : void MplsTable::ReserveMulticastLabel(uint32_t start, uint32_t end,
393 : uint8_t idx) {
394 8 : multicast_label_start_[idx] = start;
395 8 : multicast_label_end_[idx] = end;
396 8 : ReserveLabel(start, end);
397 8 : }
398 :
399 2721 : MplsLabel *MplsTable::FindMplsLabel(uint32_t label) {
400 2721 : MplsLabelKey key(label);
401 5442 : return static_cast<MplsLabel *>(Find(&key, false));
402 2721 : }
403 :
404 : // Allocate label for next-hop(interface, vrf, vlan)
405 1387 : MplsLabel *MplsTable::AllocLabel(const NextHopKey *nh_key) {
406 1387 : switch(nh_key->GetType()) {
407 1387 : case NextHop::INTERFACE:
408 : case NextHop::VLAN:
409 : case NextHop::VRF:
410 1387 : break;
411 0 : default:
412 0 : assert(0);
413 : }
414 :
415 : // Allocate label from resource manager
416 : ResourceManager::KeyPtr rkey(new NexthopIndexResourceKey(
417 1387 : agent()->resource_manager(),
418 2774 : nh_key->Clone()));
419 : uint32_t label = ((static_cast<IndexResourceData *>(agent()->resource_manager()->
420 1387 : Allocate(rkey).get()))->index());
421 1387 : assert(label != MplsTable::kInvalidLabel);
422 :
423 : // Add MplsLabel db entry
424 1387 : DBRequest req;
425 1387 : req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
426 :
427 1387 : MplsLabelKey *key = new MplsLabelKey(label);
428 1387 : req.key.reset(key);
429 :
430 1387 : MplsLabelData *data = new MplsLabelData(nh_key->Clone());
431 1387 : req.data.reset(data);
432 :
433 1387 : agent()->mpls_table()->Process(req);
434 :
435 : // Return MplsLabel db entry for nh to hold reference
436 1387 : MplsLabel *mpls_label = static_cast<MplsLabel *>
437 1387 : (agent()->mpls_table()->FindActiveEntry(key));
438 1387 : assert(mpls_label);
439 :
440 2774 : return mpls_label;
441 : }
442 :
443 3060 : void MplsTable::CheckVrLabelLimit() {
444 3060 : VrLimitExceeded &vr_limits = agent()->get_vr_limits_exceeded_map();
445 3060 : VrLimitExceeded::iterator vr_limit_itr = vr_limits.find("vr_mpls_labels");
446 3060 : if (vr_limit_itr->second == "Normal") {
447 3060 : if (label_table_.InUseIndexCount() >= ((agent()->vr_limit_high_watermark() *
448 3060 : agent()->vrouter_max_labels())/100) ) {
449 0 : vr_limit_itr->second.assign(std::string("Exceeded"));
450 0 : LOG(ERROR, "Vrouter Mpls Labels Exceeded.");
451 : }
452 0 : } else if ( vr_limit_itr->second == "Exceeded") {
453 0 : if (label_table_.InUseIndexCount() >= agent()->vrouter_max_labels()) {
454 0 : vr_limit_itr->second.assign(std::string("TableLimit"));
455 0 : LOG(ERROR, "Vrouter Mpls Lablels Table Limit Reached. Skip Label Add.");
456 0 : } else if ( label_table_.InUseIndexCount() < ((agent()->vr_limit_low_watermark() *
457 0 : agent()->vrouter_max_labels())/100) ) {
458 0 : vr_limit_itr->second.assign(std::string("Normal"));
459 : }
460 0 : } else if ( vr_limit_itr->second == "TableLimit" ) {
461 0 : if (label_table_.InUseIndexCount() <
462 0 : ((agent()->vrouter_max_labels()*95)/100) ) {
463 0 : vr_limit_itr->second.assign(std::string("Exceeded"));
464 0 : LOG(ERROR, "Vrouter Mpls Labels Exceeded.");
465 : }
466 : }
467 3060 : agent()->set_vr_limits_exceeded_map(vr_limits);
468 3060 : }
469 :
470 0 : AgentSandeshPtr MplsTable::GetAgentSandesh(const AgentSandeshArguments *args,
471 : const std::string &context) {
472 : return AgentSandeshPtr(new AgentMplsSandesh
473 0 : (context, args->GetString("type"),
474 0 : args->GetString("label")));
475 : }
476 :
477 0 : void MplsReq::HandleRequest() const {
478 0 : AgentSandeshPtr sand(new AgentMplsSandesh(context(), get_type(),
479 0 : get_label()));
480 0 : sand->DoSandesh(sand);
481 0 : }
|