forked from sonic-net/sonic-sairedis
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathComparisonLogic.cpp
More file actions
3878 lines (3084 loc) · 135 KB
/
ComparisonLogic.cpp
File metadata and controls
3878 lines (3084 loc) · 135 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "ComparisonLogic.h"
#include "VidManager.h"
#include "BestCandidateFinder.h"
#include "NotificationHandler.h"
#include "VirtualOidTranslator.h"
#include "CommandLineOptions.h"
#include "Workaround.h"
#include "swss/logger.h"
#include "meta/sai_serialize.h"
#include "meta/SaiAttributeList.h"
#include <inttypes.h>
using namespace syncd;
using namespace saimeta;
/*
* NOTE: All methods taking current and temporary view could be moved to
* transition class etc to just use class members instead of passing those
* parameters to every function.
*/
ComparisonLogic::ComparisonLogic(
_In_ std::shared_ptr<sairedis::SaiInterface> vendorSai,
_In_ std::shared_ptr<SaiSwitchInterface> sw,
_In_ std::shared_ptr<NotificationHandler> handler,
_In_ std::set<sai_object_id_t> initViewRemovedVids,
_In_ std::shared_ptr<AsicView> current,
_In_ std::shared_ptr<AsicView> temp,
_In_ std::shared_ptr<BreakConfig> breakConfig):
m_vendorSai(vendorSai),
m_switch(sw),
m_initViewRemovedVids(initViewRemovedVids),
m_current(current),
m_temp(temp),
m_handler(handler),
m_breakConfig(breakConfig)
{
SWSS_LOG_ENTER();
m_enableRefernceCountLogs = false;
// will inside filter only RID/VID to this particular switch
// TODO move outside switch ? since later could be in different ASIC_DB
m_current->m_ridToVid = m_switch->getRidToVidMap();
m_current->m_vidToRid = m_switch->getVidToRidMap();
/*
* Those calls could be calls to SAI, but when this will be separate lib
* then we would like to limit sai to minimum or reimplement getting those.
*
* TODO: This needs to be refactored and solved in other way since asic
* view can contain multiple switches.
*
* TODO: This also can be optimized using metadata.
* We need to add access to SaiSwitch in AsicView.
*/
// TODO needs to be removed and done in generic
m_current->m_defaultTrapGroupRid = m_switch->getSwitchDefaultAttrOid(SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP);
m_temp->m_defaultTrapGroupRid = m_switch->getSwitchDefaultAttrOid(SAI_SWITCH_ATTR_DEFAULT_TRAP_GROUP);
auto seed = (unsigned int)std::time(0);
SWSS_LOG_NOTICE("srand seed for switch %s: %u", sai_serialize_object_id(m_switch->getVid()).c_str(), seed);
std::srand(seed);
}
ComparisonLogic::~ComparisonLogic()
{
SWSS_LOG_ENTER();
// empty
}
void ComparisonLogic::compareViews()
{
SWSS_LOG_ENTER();
AsicView& current = *m_current;
AsicView& temp = *m_temp;
/*
* Match oids before calling populate existing objects since after
* matching oids RID and VID maps will be populated.
*/
matchOids(current, temp);
/*
* Populate existing objects to current and temp view if they don't
* exist since we are populating them when syncd starts, and when we
* switch view we don't want to loose any of those objects since during
* syncd runtime is counting on that those objects exists.
*
* TODO: If some object's will be removed like VLAN members then this
* existing objects needs to be updated in the switch!
*/
populateExistingObjects(current, temp);
checkInternalObjects(current, temp);
/*
* Call main method!
*/
if (m_enableRefernceCountLogs)
{
current.dumpRef("current START");
temp.dumpRef("temp START");
}
createPreMatchMap(current, temp);
logViewObjectCount(current, temp);
applyViewTransition(current, temp);
transferNotProcessed(current, temp);
// TODO have a method to check for not processed objects
// and maybe add them to list on processing attributes
// and move note processed objects to temporary view as well
// we need to check oid attributes as well
SWSS_LOG_NOTICE("ASIC operations to execute: %zu", current.asicGetOperationsCount());
temp.checkObjectsStatus();
SWSS_LOG_NOTICE("all temporary view objects were processed to FINAL state");
current.checkObjectsStatus();
SWSS_LOG_NOTICE("all current view objects were processed to FINAL state");
/*
* After all operations both views should look the same so number of
* rid/vid should look the same.
*/
checkMap(current, temp);
/*
* At the end number of m_soAll objects must be equal on both views. If
* some on temporary views are missing, we need to transport empty
* objects to temporary view, like queues, scheduler groups, virtual
* router, trap groups etc.
*/
if (current.m_soAll.size() != temp.m_soAll.size())
{
/*
* If this will happen that means non object id values are
* different since number of RID/VID maps is identical (previous
* check).
*
* Unlikely to be routes/neighbors/fdbs, can be traps, switch,
* vlan.
*
* TODO: For debug we will need to display differences
*/
SWSS_LOG_THROW("wrong number of all objects current: %zu vs temp %zu, FIXME",
current.m_soAll.size(),
temp.m_soAll.size());
}
}
/**
* @brief Match OIDs on temporary and current view using VIDs.
*
* For all OID objects in temporary view we match all VID's in the current
* view, some objects will have the same VID's in both views (eg. ports), in
* that case their RID's also are the same, so in that case we mark both
* objects in both views as "MATCHED" which will speed up search comparison
* logic for those type of objects.
*
* @param currentView Current view.
* @param temporaryView Temporary view.
*/
void ComparisonLogic::matchOids(
_In_ AsicView ¤tView,
_In_ AsicView &temporaryView)
{
SWSS_LOG_ENTER();
auto coldBootDiscoveredVids = m_switch->getColdBootDiscoveredVids();
for (const auto &temporaryIt: temporaryView.m_oOids)
{
sai_object_id_t temporaryVid = temporaryIt.first;
const auto ¤tIt = currentView.m_oOids.find(temporaryVid);
if (currentIt == currentView.m_oOids.end())
{
continue;
}
sai_object_id_t vid = temporaryVid;
sai_object_id_t rid = currentView.m_vidToRid.at(vid);
// save VID and RID in temporary view
temporaryView.m_ridToVid[rid] = vid;
temporaryView.m_vidToRid[vid] = rid;
// set both objects status as matched
temporaryIt.second->setObjectStatus(SAI_OBJECT_STATUS_MATCHED);
currentIt->second->setObjectStatus(SAI_OBJECT_STATUS_MATCHED);
SWSS_LOG_INFO("matched %s RID %s VID %s",
currentIt->second->m_str_object_type.c_str(),
sai_serialize_object_id(rid).c_str(),
sai_serialize_object_id(vid).c_str());
if (coldBootDiscoveredVids.find(vid) == coldBootDiscoveredVids.end())
{
auto ot = currentIt->second->getObjectType();
switch (ot)
{
case SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP:
case SAI_OBJECT_TYPE_SCHEDULER_GROUP:
case SAI_OBJECT_TYPE_QUEUE:
case SAI_OBJECT_TYPE_PORT:
break;
default:
// Should we also add check if also not in removed?
// This is for case of only GET:
// 1. cold boot:
// - OA assigns buffer profile to Queue
// 2. warm boot:
// - OA do GET on Queue and got previous buffer profile
// - OA assigns new buffer profile on Queue
//
// Question: what should happen to old buffer profile? should it be removed?
// No, since OA still hold's the reference to that VID and may use it later.
SWSS_LOG_INFO("matched %s VID %s was not in cold boot, possible only GET?",
sai_serialize_object_id(vid).c_str(),
currentIt->second->m_str_object_type.c_str());
break;
}
}
}
SWSS_LOG_NOTICE("matched oids");
}
/**
* @brief Check internal objects.
*
* During warm boot, when switch restarted we expect that switch will have the
* same number of objects like before boot, and all vendor OIDs (RIDs) will be
* exactly the same as before reboot.
*
* If OIDs are not the same, then this is a vendor bug.
*
* Exception of this rule is when orchagent will be restarted and it will add
* some more objects or remove some objects.
*
* We take special care here about INGRESS_PRIORITY_GROUPS, SCHEDULER_GROUPS
* and QUEUES, since those are internal objects created by vendor when switch
* is instantiated.
*
* @param currentView Current view.
* @param temporaryView Temporary view.
*/
void ComparisonLogic::checkInternalObjects(
_In_ const AsicView &cv,
_In_ const AsicView &tv)
{
SWSS_LOG_ENTER();
SWSS_LOG_NOTICE("check internal objects");
std::vector<sai_object_type_t> ots =
{
SAI_OBJECT_TYPE_QUEUE,
SAI_OBJECT_TYPE_SCHEDULER_GROUP,
SAI_OBJECT_TYPE_INGRESS_PRIORITY_GROUP
};
for (auto ot: ots)
{
auto cot = cv.getObjectsByObjectType(ot);
auto tot = tv.getObjectsByObjectType(ot);
auto sot = sai_serialize_object_type(ot);
if (cot.size() != tot.size())
{
SWSS_LOG_WARN("different number of objects %s, curr: %zu, tmp %zu (not expected if warm boot)",
sot.c_str(),
cot.size(),
tot.size());
}
for (auto o: cot)
if (o->getObjectStatus() != SAI_OBJECT_STATUS_MATCHED)
SWSS_LOG_ERROR("object status is not MATCHED on curr: %s:%s",
sot.c_str(), o->m_str_object_id.c_str());
for (auto o: tot)
if (o->getObjectStatus() != SAI_OBJECT_STATUS_MATCHED)
SWSS_LOG_ERROR("object status is not MATCHED on temp: %s:%s",
sot.c_str(), o->m_str_object_id.c_str());
}
}
void ComparisonLogic::checkMatchedPorts(
_In_ const AsicView &temporaryView)
{
SWSS_LOG_ENTER();
/*
* We should check if all PORT's and SWITCH are matched since this is our
* starting point for comparison logic.
*/
auto ports = temporaryView.getObjectsByObjectType(SAI_OBJECT_TYPE_PORT);
for (const auto &p: ports)
{
if (p->getObjectStatus() == SAI_OBJECT_STATUS_MATCHED)
{
continue;
}
/*
* If that happens then:
*
* - we have a bug in our matching port logic, or
* - we need to remap ports VID/RID after syncd restart, or
* - after changing switch profile we have different number of ports
*
* In any of those cased this is FATAL and needs to be addressed,
* currently we don't expect port OIDs to change, there is check on
* syncd start for that, and our goal is that each time we will load
* the same profile for switch so different number of ports should be
* ruled out.
*/
SWSS_LOG_THROW("port %s object status is not MATCHED (%d)", p->m_str_object_id.c_str(), p->getObjectStatus());
}
SWSS_LOG_NOTICE("all ports are matched");
}
/**
* @brief Process object attributes for view transition.
*
* Since each object can contain attributes (or non id struct object can
* contain oids inside struct) they need to be processed first recursively and
* they need to be in FINAL state before processing temporary view further.
*
* This processing may result in changes in current view like removing and
* recreating or adding new objects depends on transitions.
*
* @param currentView Current view.
* @param temporaryView Temporary view.
* @param temporaryObj Temporary object.
*/
void ComparisonLogic::procesObjectAttributesForViewTransition(
_In_ AsicView ¤tView,
_In_ AsicView &temporaryView,
_In_ const std::shared_ptr<SaiObj> &temporaryObj)
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("%s %s", temporaryObj->m_str_object_type.c_str(), temporaryObj->m_str_object_id.c_str());
/*
* First we need to make sure if all attributes of this temporary object
* are in FINAL or MATCHED state, then we can process this object and find
* best match in current asic view.
*/
for (auto &at: temporaryObj->getAllAttributes())
{
auto &attribute = at.second;
SWSS_LOG_INFO("attr %s", attribute->getStrAttrId().c_str());
/*
* For each object id in attributes go recursively to match those
* objects.
*/
for (auto vid: attribute->getOidListFromAttribute())
{
if (vid == SAI_NULL_OBJECT_ID)
{
continue;
}
SWSS_LOG_INFO("- processing attr VID %s", sai_serialize_object_id(vid).c_str());
auto tempParent = temporaryView.m_oOids.at(vid);
processObjectForViewTransition(currentView, temporaryView, tempParent); // recursion
/*
* Temporary object here is never changed, even if we do recursion
* here all that could been removed are objects in current view
* tree so we don't need to worry about any temporary object
* removal.
*/
}
}
if (temporaryObj->isOidObject())
{
return;
}
/*
* For non object id types like NEIGHBOR or ROUTE they have object id
* inside object struct entry, they also need to be processed, in SAI 1.0
* this can be automated since we have metadata for those structs.
*/
for (size_t j = 0; j < temporaryObj->m_info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = temporaryObj->m_info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
sai_object_id_t vid = m->getoid(&temporaryObj->m_meta_key);
SWSS_LOG_INFO("- processing %s (%s) VID %s",
temporaryObj->m_str_object_type.c_str(),
m->membername,
sai_serialize_object_id(vid).c_str());
auto structObject = temporaryView.m_oOids.at(vid);
processObjectForViewTransition(currentView, temporaryView, structObject); // recursion
}
}
void ComparisonLogic::bringNonRemovableObjectToDefaultState(
_In_ AsicView ¤tView,
_In_ const std::shared_ptr<SaiObj> ¤tObj)
{
SWSS_LOG_ENTER();
for (const auto &it: currentObj->getAllAttributes())
{
const auto &attr = it.second;
const auto &meta = attr->getAttrMetadata();
if (!SAI_HAS_FLAG_CREATE_AND_SET(meta->flags))
{
SWSS_LOG_THROW("attribute %s is not CREATE_AND_SET, bug?", meta->attridname);
}
if (meta->defaultvaluetype == SAI_DEFAULT_VALUE_TYPE_NONE)
{
SWSS_LOG_THROW("attribute %s default value type is NONE, bug?", meta->attridname);
}
auto defaultValueAttr = BestCandidateFinder::getSaiAttrFromDefaultValue(currentView, m_switch, *meta);
if (defaultValueAttr == nullptr)
{
SWSS_LOG_THROW("Can't get default value for present current attr %s:%s, FIXME",
meta->attridname,
attr->getStrAttrValue().c_str());
}
if (attr->getStrAttrValue() == defaultValueAttr->getStrAttrValue())
{
/*
* If current value is the same as default value no need to
* generate ASIC update command.
*/
continue;
}
currentView.asicSetAttribute(currentObj, defaultValueAttr);
}
currentObj->setObjectStatus(SAI_OBJECT_STATUS_FINAL);
/*
* TODO Revisit.
*
* Problem here is that default trap group is used and we build references
* for it, so it will not be "removed" when processing, since it's default
* object so it will not be processed, and also it can't be removed since
* it's default object.
*/
}
/**
* @brief Indicates whether object can be removed.
*
* This method should be used on oid objects, all non oid objects (like route,
* neighbor, etc.) can be safely removed.
*
* @param currentObj Current object to be examined.
*
* @return True if object can be removed, false otherwise.
*/
bool ComparisonLogic::isNonRemovableObject(
_In_ const AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ const std::shared_ptr<const SaiObj> ¤tObj)
{
SWSS_LOG_ENTER();
if (currentObj->isOidObject())
{
sai_object_id_t rid = currentView.m_vidToRid.at(currentObj->getVid());
return m_switch->isNonRemovableRid(rid);
}
/*
* Object is non object id, like ROUTE_ENTRY etc, can be removed.
*/
return false;
}
void ComparisonLogic::removeExistingObjectFromCurrentView(
_In_ AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ const std::shared_ptr<SaiObj> ¤tObj)
{
SWSS_LOG_ENTER();
if (currentObj->getObjectStatus() != SAI_OBJECT_STATUS_NOT_PROCESSED)
{
SWSS_LOG_THROW("FATAL: removing object with status: %d, logic error", currentObj->getObjectStatus());
}
/*
* This decreasing VID reference will be hard when actual reference will
* be one of default objects like CPU or default trap group when we "bring
* default value" or maybe in oid case we will not bring default values and
* just remove and recreate.
*/
if (currentObj->isOidObject())
{
int count = currentView.getVidReferenceCount(currentObj->getVid());
if (count != 0)
{
/*
* If references count is not zero, we need to remove child
* first for that we need dependency tree, not supported yet.
*
* NOTE: Object can be non removable and can have reference on it.
*/
SWSS_LOG_THROW("can't remove existing object %s:%s since reference count is %d, FIXME",
currentObj->m_str_object_type.c_str(),
currentObj->m_str_object_id.c_str(),
count);
}
}
/*
* If some object can't be removed from current view and it's missing from
* temp, then it needs to be transferred to temp as well and bring to
* default values.
*
* First we need to check if object can be removed, like port's cant be
* removed, vlan 1, queues, ingress pg etc.
*
* Remove for those objects is not supported now lets bring back
* object to default state.
*
* For oid values we can figure out if we would have list of
* defaults which can be removed and which can't and use list same
* for queues, schedulers etc.
*
* We could use switch here and non created objects to make this simpler.
*/
if (currentObj->getObjectType() == SAI_OBJECT_TYPE_SWITCH)
{
/*
* Remove switch is much simpler, we just need check if switch doesn't
* exist in temporary view, and we can just remove it. In here when
* attributes don't match it's much complicated.
*/
SWSS_LOG_THROW("switch can't be removed from current view, not supported yet");
}
if (isNonRemovableObject(currentView, temporaryView, currentObj))
{
bringNonRemovableObjectToDefaultState(currentView, currentObj);
}
else
{
/*
* Asic remove object is decreasing reference count on non object ID if
* current object is non object id, release existing links only looks
* into attributes.
*/
currentView.asicRemoveObject(currentObj);
currentObj->setObjectStatus(SAI_OBJECT_STATUS_REMOVED);
}
}
sai_object_id_t ComparisonLogic::translateTemporaryVidToCurrentVid(
_In_ const AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ sai_object_id_t tvid)
{
SWSS_LOG_ENTER();
/*
* This method is used to translate temporary VID to current VID using RID
* which should be present in both views. If RID doesn't exist, then we
* check whether object was created if so, then we return temporary VID
* instead of creating new current VID and we don't need to track mapping
* of those vids not having actual RID. This function should be used only
* when we creating new objects in current view.
*/
auto temporaryIt = temporaryView.m_vidToRid.find(tvid);
if (temporaryIt == temporaryView.m_vidToRid.end())
{
/*
* This can also happen when this VID object was created dynamically,
* and don't have RID assigned yet, in that case we should use exact
* same VID. We need to get temporary object for that VID and see if
* flag created is set, and same VID must then exists in current view.
*/
/*
* We need to find object that has this vid
*/
auto tempIt = temporaryView.m_oOids.find(tvid);
if (tempIt == temporaryView.m_oOids.end())
{
SWSS_LOG_THROW("temporary VID %s not found in temporary view",
sai_serialize_object_id(tvid).c_str());
}
const auto &tempObj = tempIt->second;
if (tempObj->m_createdObject)
{
SWSS_LOG_DEBUG("translated temp VID %s to current, since object was created",
sai_serialize_object_id(tvid).c_str());
return tvid;
}
SWSS_LOG_THROW("VID %s was not found in temporary view, was object created? FIXME",
sai_serialize_object_id(tvid).c_str());
}
sai_object_id_t rid = temporaryIt->second;
auto currentIt = currentView.m_ridToVid.find(rid);
if (currentIt == currentView.m_ridToVid.end())
{
SWSS_LOG_THROW("RID %s was not found in current view",
sai_serialize_object_id(rid).c_str());
}
sai_object_id_t cvid = currentIt->second;
SWSS_LOG_DEBUG("translated temp VID %s using RID %s to current VID %s",
sai_serialize_object_id(tvid).c_str(),
sai_serialize_object_id(rid).c_str(),
sai_serialize_object_id(cvid).c_str());
return cvid;
}
std::shared_ptr<SaiAttr> ComparisonLogic::translateTemporaryVidsToCurrentVids(
_In_ const AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ const std::shared_ptr<SaiObj> ¤tObj,
_In_ const std::shared_ptr<SaiAttr> &inattr)
{
SWSS_LOG_ENTER();
/*
* We are creating copy here since we will modify contents of that
* attribute.
*/
auto attr = std::make_shared<SaiAttr>(inattr->getStrAttrId(), inattr->getStrAttrValue());
if (!attr->isObjectIdAttr())
{
return attr;
}
/*
* We need temporary VID translation to current view RID.
*
* We also need simpler version that will translate simple VID for
* oids present inside non object id structs.
*/
uint32_t count = 0;
sai_object_id_t *objectIdList = NULL;
auto &at = *attr->getRWSaiAttr();
switch (attr->getAttrMetadata()->attrvaluetype)
{
case SAI_ATTR_VALUE_TYPE_OBJECT_ID:
count = 1;
objectIdList = &at.value.oid;
break;
case SAI_ATTR_VALUE_TYPE_OBJECT_LIST:
count = at.value.objlist.count;
objectIdList = at.value.objlist.list;
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_ID:
if (at.value.aclfield.enable)
{
count = 1;
objectIdList = &at.value.aclfield.data.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_FIELD_DATA_OBJECT_LIST:
if (at.value.aclfield.enable)
{
count = at.value.aclfield.data.objlist.count;
objectIdList = at.value.aclfield.data.objlist.list;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_ID:
if (at.value.aclaction.enable)
{
count = 1;
objectIdList = &at.value.aclaction.parameter.oid;
}
break;
case SAI_ATTR_VALUE_TYPE_ACL_ACTION_DATA_OBJECT_LIST:
if (at.value.aclaction.enable)
{
count = at.value.aclaction.parameter.objlist.count;
objectIdList = at.value.aclaction.parameter.objlist.list;
}
break;
default:
// TODO check is is oid object and throw as not translated
break;
}
for (uint32_t i = 0; i < count; ++i)
{
sai_object_id_t tvid = objectIdList[i];
if (tvid == SAI_NULL_OBJECT_ID)
{
continue;
}
/*
* Do actual translation.
*/
objectIdList[i] = translateTemporaryVidToCurrentVid(currentView, temporaryView, tvid);
}
/*
* Since we probably performed updates on this attribute, since VID was
* exchanged, we need to update value string of that attribute.
*/
attr->updateValue();
return attr;
}
/**
* @brief Set attribute on current object
*
* This function will set given attribute to current object adding new
* attribute or replacing existing one. Given attribute can be either one
* temporary attribute missing or different from current object object or
* default attribute value if we need to bring some attribute to default value.
*
* @param currentView Current view.
* @param temporaryView Temporary view.
* @param currentObj Current object on which we set attribute.
* @param inattr Attribute to be set on current object.
*/
void ComparisonLogic::setAttributeOnCurrentObject(
_In_ AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ const std::shared_ptr<SaiObj> ¤tObj,
_In_ const std::shared_ptr<SaiAttr> &inattr)
{
SWSS_LOG_ENTER();
/*
* At the beginning just small assert to check if object is create and set.
*/
const auto meta = inattr->getAttrMetadata();
if (!SAI_HAS_FLAG_CREATE_AND_SET(meta->flags))
{
SWSS_LOG_THROW("can't set attribute %s on current object %s:%s since it's not CREATE_AND_SET",
meta->attridname,
currentObj->m_str_object_type.c_str(),
currentObj->m_str_object_id.c_str());
}
/*
* NOTE: Since attribute we SET can be OID attribute, and that can be a VID
* or list of VIDs from temporary view. So after this "set" operation we
* will end up with MIXED VIDs on current view, some object will contain
* VIDs from temporary view, and this can lead to fail in
* translate_vid_to_rid since we will need to look inside two views to find
* right RID.
*
* We need a flag to say that VID is for object that was created
* and we can mix only those VID's for objects that was created.
*
* In here we need to translate attribute VIDs to current VIDs to keep
* track in dependency tree, since if we use temporary VID that will point
* to the same RID then we will lost track in dependency tree of that VID
* reference count.
*
* This should also done for object id's inside non object ids.
*/
std::shared_ptr<SaiAttr> attr = translateTemporaryVidsToCurrentVids(currentView, temporaryView, currentObj, inattr);
currentView.asicSetAttribute(currentObj, attr);
}
/**
* @brief Create new object from temporary object.
*
* Since best match was not found we need to create a brand new object and put
* it into current view as well.
*
* @param currentView Current view.
* @param temporaryView Temporary view.
* @param temporaryObj Temporary object to be cloned to current view.
*/
void ComparisonLogic::createNewObjectFromTemporaryObject(
_In_ AsicView ¤tView,
_In_ const AsicView &temporaryView,
_In_ const std::shared_ptr<SaiObj> &temporaryObj)
{
SWSS_LOG_ENTER();
SWSS_LOG_INFO("creating object %s:%s",
temporaryObj->m_str_object_type.c_str(),
temporaryObj->m_str_object_id.c_str());
/*
* This trap can be default trap group, so let's check if it's, then we
* can't create it, we need to set new attributes if that possible. But
* this case should not happen since on syncd start we are putting default
* trap group to asic view, so if user will query default one, they will be
* matched by RID.
*
* Default trap group is transferred to view on init if it doesn't exist.
*
* There should be no such action here, since this scenario would mean that
* there is default switch object in temporary view, but not in current
* view. All default objects are put to ASIC state table when switch is
* created. So what can happen is opposite scenario.
*/
/*
* NOTE: Since attributes we pass to create can be OID attributes, and that
* can be a VID or list of VIDs from temporary view. So after this create
* operation we will end up with MIXED VIDs on current view, some object
* will contain VIDs from temporary view, and this can lead to fail in
* translate_vid_to_rid since we will need to look inside two views to find
* right RID.
*
* We need a flag to say that VID is for object that was created and we can
* mix only those VID's for objects that was created.
*
* In here we need to translate attribute VIDs to current VIDs to keep
* track in dependency tree, since if we use temporary VID that will point
* to the same RID then we will lost track in dependency tree of that VID
* reference count.
*
* This should also be done for object id's inside non object ids.
*/
/*
* We need to loop through all attributes and create copy of this object
* and translate all attributes for getting correct VIDs like in set
* operation, we can't use VID's from temporary view to not mix them with
* current view, except created object ID's, since we won't be creating any
* new VID on the way (but we could) maybe we can do that later - but for
* that we will need some kind of RID which would later need to be removed.
*/
std::shared_ptr<SaiObj> currentObj = std::make_shared<SaiObj>();
/*
* TODO Find out better way to do this, copy operator ?
*/
currentObj->m_str_object_type = temporaryObj->m_str_object_type;
currentObj->m_str_object_id = temporaryObj->m_str_object_id; // temporary VID / non object id
currentObj->m_meta_key = temporaryObj->m_meta_key; // temporary VID / non object id
currentObj->m_info = temporaryObj->m_info;
if (!temporaryObj->isOidObject())
{
/*
* Since object contains OID inside struct, this OID may already exist
* in current view, so we need to do translation here.
*/
for (size_t j = 0; j < currentObj->m_info->structmemberscount; ++j)
{
const sai_struct_member_info_t *m = currentObj->m_info->structmembers[j];
if (m->membervaluetype != SAI_ATTR_VALUE_TYPE_OBJECT_ID)
{
continue;
}
sai_object_id_t vid = m->getoid(¤tObj->m_meta_key);
vid = translateTemporaryVidToCurrentVid(currentView, temporaryView, vid);
m->setoid(¤tObj->m_meta_key, vid);
/*
* Bind new vid reference is already done inside asicCreateObject.
*/
}
/*
* Since it's possible that object id may had been changed, we need to
* update string as well.
*/
switch (temporaryObj->getObjectType())
{
case SAI_OBJECT_TYPE_ROUTE_ENTRY:
currentObj->m_str_object_id = sai_serialize_route_entry(currentObj->m_meta_key.objectkey.key.route_entry);
break;
case SAI_OBJECT_TYPE_NEIGHBOR_ENTRY:
currentObj->m_str_object_id = sai_serialize_neighbor_entry(currentObj->m_meta_key.objectkey.key.neighbor_entry);
break;
case SAI_OBJECT_TYPE_FDB_ENTRY:
currentObj->m_str_object_id = sai_serialize_fdb_entry(currentObj->m_meta_key.objectkey.key.fdb_entry);
break;