@@ -26,6 +26,64 @@ cfg::AggregatePortMember makePortMember(int32_t port, cfg::LacpPortRate rate) {
2626 return aggMember;
2727}
2828
29+ namespace {
30+ // A VLAN left with no ports must be dropped; otherwise it diverges between cold
31+ // boot and warmboot.
32+ void removeUnreferencedVlans (
33+ cfg::SwitchConfig* config,
34+ const std::set<int32_t >& memberOldVlans,
35+ int32_t aggVlan) {
36+ // Check ASIC type. Do not perform cleanup for Cisco chips.
37+ bool isCiscoAsic = false ;
38+ for (const auto & [_, switchInfo] :
39+ *config->switchSettings ()->switchIdToSwitchInfo ()) {
40+ auto asicType = *switchInfo.asicType ();
41+ if (asicType == cfg::AsicType::ASIC_TYPE_EBRO ||
42+ asicType == cfg::AsicType::ASIC_TYPE_YUBA ||
43+ asicType == cfg::AsicType::ASIC_TYPE_P200 ||
44+ asicType == cfg::AsicType::ASIC_TYPE_GARONNE ||
45+ asicType == cfg::AsicType::ASIC_TYPE_G202X ) {
46+ isCiscoAsic = true ;
47+ break ;
48+ }
49+ }
50+ if (isCiscoAsic) {
51+ return ;
52+ }
53+
54+ std::set<int32_t > stillReferenced;
55+ for (const auto & vlanPort : *config->vlanPorts ()) {
56+ stillReferenced.insert (vlanPort.vlanID ().value ());
57+ }
58+
59+ for (auto oldVlan : memberOldVlans) {
60+ if (oldVlan == aggVlan || stillReferenced.contains (oldVlan) ||
61+ (oldVlan == *config->defaultVlan ())) {
62+ continue ;
63+ }
64+
65+ auto & vlans = *config->vlans ();
66+ vlans.erase (
67+ std::remove_if (
68+ vlans.begin (),
69+ vlans.end (),
70+ [&](const auto & v) { return v.id ().value () == oldVlan; }),
71+ vlans.end ());
72+
73+ auto & intfs = *config->interfaces ();
74+ intfs.erase (
75+ std::remove_if (
76+ intfs.begin (),
77+ intfs.end (),
78+ [&](const auto & i) {
79+ return i.type ().value () == cfg::InterfaceType::VLAN &&
80+ i.vlanID ().value () == oldVlan;
81+ }),
82+ intfs.end ());
83+ }
84+ }
85+ } // namespace
86+
2987void addAggPort (
3088 int key,
3189 const std::vector<int32_t >& ports,
@@ -54,15 +112,22 @@ void addAggPort(
54112 // Set VLAN for all members to be the same
55113 std::set<uint32_t > memberPorts (ports.begin (), ports.end ());
56114 std::optional<int32_t > aggVlan;
115+ std::set<int32_t > memberOldVlans;
57116 for (auto & vlanPort : *config->vlanPorts ()) {
58117 if (memberPorts.contains (vlanPort.logicalPort ().value ())) {
118+ int32_t oldVlan = vlanPort.vlanID ().value ();
119+ memberOldVlans.insert (oldVlan);
59120 if (!aggVlan) {
60- aggVlan = vlanPort. vlanID (). value () ;
121+ aggVlan = oldVlan ;
61122 }
62123 vlanPort.vlanID () = *aggVlan;
63124 }
64125 }
65126
127+ if (aggVlan.has_value ()) {
128+ removeUnreferencedVlans (config, memberOldVlans, *aggVlan);
129+ }
130+
66131 if (aggregatePortType == cfg::AggregatePortType::LAG_PORT ) {
67132 // Set ingress VLAN for all members to be the same
68133 for (auto & port : *config->ports ()) {
0 commit comments