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