Skip to content

Commit

Permalink
[MirrorOrch]: Mirror Session Retention across Warm Reboot
Browse files Browse the repository at this point in the history
After warm reboot, it is expected that the monitor port of
the mirror session is retained - no changing on the monitor
port withint the ECMP group members and the LAG members. This
is due to the general of the sairedis comparison logic and
the minimalization of SAI function calls during reconciliation.

Changes:
1. Add bake() and postBake() functions in MirrorOrch
   bake() function retrieves the state database information
   and get the VLAN + monitor port information.
   postBake() function leverages the information and recovers
   the active mirror sessions the same as before warm reboot.
2. state database format change
   Instead of storing the object ID of the monitor port, store
   the alias of the monitor port.
   Instead of storing true/false of VLAN header, store the VLAN
   ID.

Signed-off-by: Shu0T1an ChenG <shuche@microsoft.com>
  • Loading branch information
Shu0t1an Cheng committed Sep 13, 2019
1 parent 313ef5c commit 29b4999
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 31 deletions.
215 changes: 192 additions & 23 deletions orchagent/mirrororch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "swssnet.h"
#include "converter.h"
#include "mirrororch.h"
#include "tokenize.h"

#define MIRROR_SESSION_STATUS "status"
#define MIRROR_SESSION_STATUS_ACTIVE "active"
Expand All @@ -23,7 +24,7 @@
#define MIRROR_SESSION_DST_MAC_ADDRESS "dst_mac"
#define MIRROR_SESSION_MONITOR_PORT "monitor_port"
#define MIRROR_SESSION_ROUTE_PREFIX "route_prefix"
#define MIRROR_SESSION_VLAN_HEADER_VALID "vlan_header_valid"
#define MIRROR_SESSION_VLAN_ID "vlan_id"
#define MIRROR_SESSION_POLICER "policer"

#define MIRROR_SESSION_DEFAULT_VLAN_PRI 0
Expand Down Expand Up @@ -75,10 +76,145 @@ MirrorOrch::MirrorOrch(TableConnector stateDbConnector, TableConnector confDbCon
m_fdbOrch->attach(this);
}

bool MirrorOrch::bake()
{
SWSS_LOG_ENTER();

// Freeze the route update during orchagent restoration
m_freezeUpdate = true;

deque<KeyOpFieldsValuesTuple> entries;
vector<string> keys;
m_mirrorTable.getKeys(keys);
for (const auto &key : keys)
{
vector<FieldValueTuple> tuples;
m_mirrorTable.get(key, tuples);

bool active = false;
string monitor_port;
string vlan_id;

for (const auto &tuple : tuples)
{
if (fvField(tuple) == MIRROR_SESSION_STATUS)
{
active = fvValue(tuple) == MIRROR_SESSION_STATUS_ACTIVE;
}
else if (fvField(tuple) == MIRROR_SESSION_MONITOR_PORT)
{
monitor_port = fvValue(tuple);
}
else if (fvField(tuple) == MIRROR_SESSION_VLAN_ID)
{
vlan_id = fvValue(tuple);
}
}

if (!active)
{
continue;
}

SWSS_LOG_NOTICE("Found mirror session %s active before warm reboot");

// Recover saved active session's monitor port
m_recoverySessionPortMap.emplace(key, vlan_id + ":" + monitor_port);
}

return Orch::bake();
}

bool MirrorOrch::postBake()
{
SWSS_LOG_ENTER();

SWSS_LOG_NOTICE("Start MirrorOrch post-baking");

for (auto it = m_syncdMirrors.begin(); it != m_syncdMirrors.end(); ++it)
{
const string name = it->first;
auto& session = it->second;

if (m_recoverySessionPortMap.find(name) != m_recoverySessionPortMap.end())
{
auto tokens = tokenize(m_recoverySessionPortMap[name], ':');
string vlan_id = tokens[0];
string alias = tokens[1];

SWSS_LOG_NOTICE("Recover mirror session %s with monitor port %s",
name.c_str(), alias.c_str());

Port port;
m_portsOrch->getPort(alias, port);

// If the port belongs to a VLAN
if (vlan_id != "0")
{
Port vlan;
m_portsOrch->getPort("Vlan" + vlan_id, vlan);

NeighborEntry neighbor_entry;
MacAddress mac;
m_neighOrch->getNeighborEntry(vlan.m_alias, neighbor_entry, mac);

SWSS_LOG_NOTICE("Monitor port %s belongs to neighbor %s with IP %s",
port.m_alias.c_str(), vlan.m_alias.c_str(),
neighbor_entry.ip_address.to_string().c_str());

session.nexthopInfo.nexthop = neighbor_entry.ip_address;
}
// If the port belongs to a LAG
if (port.m_lag_id)
{
Port lag;
m_portsOrch->getPort(port.m_lag_id, lag);

NeighborEntry neighbor_entry;
MacAddress mac;
m_neighOrch->getNeighborEntry(lag.m_alias, neighbor_entry, mac);

SWSS_LOG_NOTICE("Monitor port %s belongs to neighbor %s with IP %s",
port.m_alias.c_str(), lag.m_alias.c_str(),
neighbor_entry.ip_address.to_string().c_str());

session.nexthopInfo.nexthop = neighbor_entry.ip_address;
}
else
{
NeighborEntry neighbor_entry;
MacAddress mac;
m_neighOrch->getNeighborEntry(port.m_alias, neighbor_entry, mac);

SWSS_LOG_NOTICE("Neighbor %s has IP %s",
port.m_alias.c_str(),
neighbor_entry.ip_address.to_string().c_str());

session.nexthopInfo.nexthop = neighbor_entry.ip_address;
}

updateSession(name, session);
}
}

// Clean up the recovery cache
m_recoverySessionPortMap.clear();

// Unfreeze the route update
m_freezeUpdate = false;

return Orch::postBake();
}

void MirrorOrch::update(SubjectType type, void *cntx)
{
SWSS_LOG_ENTER();

if (m_freezeUpdate)
{
return;
}

assert(cntx);

switch(type) {
Expand Down Expand Up @@ -320,10 +456,11 @@ void MirrorOrch::setSessionState(const string& name, const MirrorEntry& session,
{
SWSS_LOG_ENTER();

SWSS_LOG_INFO("Setting mirroring sessions %s state\n", name.c_str());
SWSS_LOG_INFO("Update mirroring sessions %s state", name.c_str());

vector<FieldValueTuple> fvVector;
string value;

if (attr.empty() || attr == MIRROR_SESSION_STATUS)
{
value = session.status ? MIRROR_SESSION_STATUS_ACTIVE : MIRROR_SESSION_STATUS_INACTIVE;
Expand All @@ -332,8 +469,9 @@ void MirrorOrch::setSessionState(const string& name, const MirrorEntry& session,

if (attr.empty() || attr == MIRROR_SESSION_MONITOR_PORT)
{
value = sai_serialize_object_id(session.neighborInfo.portId);
fvVector.emplace_back(MIRROR_SESSION_MONITOR_PORT, value);
Port port;
m_portsOrch->getPort(session.neighborInfo.portId, port);
fvVector.emplace_back(MIRROR_SESSION_MONITOR_PORT, port.m_alias);
}

if (attr.empty() || attr == MIRROR_SESSION_DST_MAC_ADDRESS)
Expand All @@ -348,10 +486,10 @@ void MirrorOrch::setSessionState(const string& name, const MirrorEntry& session,
fvVector.emplace_back(MIRROR_SESSION_ROUTE_PREFIX, value);
}

if (attr.empty() || attr == MIRROR_SESSION_VLAN_HEADER_VALID)
if (attr.empty() || attr == MIRROR_SESSION_VLAN_ID)
{
value = to_string(session.neighborInfo.port.m_type == Port::VLAN);
fvVector.emplace_back(MIRROR_SESSION_VLAN_HEADER_VALID, value);
value = to_string(session.neighborInfo.port.m_vlan_info.vlan_id);
fvVector.emplace_back(MIRROR_SESSION_VLAN_ID, value);
}

m_mirrorTable.set(name, fvVector);
Expand Down Expand Up @@ -396,32 +534,60 @@ bool MirrorOrch::getNeighborInfo(const string& name, MirrorEntry& session)
return false;
}

// Get the firt member of the LAG
Port member;
const auto& first_member_alias = *session.neighborInfo.port.m_members.begin();
m_portsOrch->getPort(first_member_alias, member);
// Recover the monitor port picked before warm reboot
if (m_recoverySessionPortMap.find(name) != m_recoverySessionPortMap.end())
{
string alias = tokenize(m_recoverySessionPortMap[name], ':')[1];
Port member;
m_portsOrch->getPort(alias, member);

session.neighborInfo.portId = member.m_port_id;
}
else
{
// Get the firt member of the LAG
Port member;
string first_member_alias = *session.neighborInfo.port.m_members.begin();
m_portsOrch->getPort(first_member_alias, member);

session.neighborInfo.portId = member.m_port_id;
}

session.neighborInfo.portId = member.m_port_id;
return true;
}
case Port::VLAN:
{
SWSS_LOG_NOTICE("Get mirror session destination IP neighbor VLAN %d",
session.neighborInfo.port.m_vlan_info.vlan_id);
Port member;
if (!m_fdbOrch->getPort(session.neighborInfo.mac, session.neighborInfo.port.m_vlan_info.vlan_id, member))

// Recover the monitor port picked before warm reboot
if (m_recoverySessionPortMap.find(name) != m_recoverySessionPortMap.end())
{
SWSS_LOG_NOTICE("Waiting to get FDB entry MAC %s under VLAN %s",
session.neighborInfo.mac.to_string().c_str(),
session.neighborInfo.port.m_alias.c_str());
return false;
string alias = tokenize(m_recoverySessionPortMap[name], ':')[1];
Port member;
m_portsOrch->getPort(alias, member);

session.neighborInfo.portId = member.m_port_id;
}
else
{
// Update monitor port
session.neighborInfo.portId = member.m_port_id;
return true;
Port member;
if (!m_fdbOrch->getPort(session.neighborInfo.mac,
session.neighborInfo.port.m_vlan_info.vlan_id, member))
{
SWSS_LOG_NOTICE("Waiting to get FDB entry MAC %s under VLAN %s",
session.neighborInfo.mac.to_string().c_str(),
session.neighborInfo.port.m_alias.c_str());
return false;
}
else
{
// Update monitor port
session.neighborInfo.portId = member.m_port_id;
}
}

return true;
}
default:
{
Expand Down Expand Up @@ -741,7 +907,7 @@ bool MirrorOrch::updateSessionType(const string& name, MirrorEntry& session)
SWSS_LOG_NOTICE("Update mirror session %s VLAN to %s",
name.c_str(), session.neighborInfo.port.m_alias.c_str());

setSessionState(name, session, MIRROR_SESSION_VLAN_HEADER_VALID);
setSessionState(name, session, MIRROR_SESSION_VLAN_ID);

return true;
}
Expand Down Expand Up @@ -782,6 +948,9 @@ void MirrorOrch::updateNextHop(const NextHopUpdate& update)

if (update.nexthopGroup != IpAddresses())
{
SWSS_LOG_INFO(" next hop IPs: %s", update.nexthopGroup.to_string().c_str());

// Pick the first one from the next hop group
session.nexthopInfo.nexthop = *update.nexthopGroup.getIpAddresses().begin();
}
else
Expand Down Expand Up @@ -991,7 +1160,7 @@ void MirrorOrch::doTask(Consumer& consumer)
}
else
{
SWSS_LOG_ERROR("Unknown operation type %s\n", op.c_str());
SWSS_LOG_ERROR("Unknown operation type %s", op.c_str());
}

consumer.m_toSync.erase(it++);
Expand Down
6 changes: 6 additions & 0 deletions orchagent/mirrororch.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ class MirrorOrch : public Orch, public Observer, public Subject
MirrorOrch(TableConnector appDbConnector, TableConnector confDbConnector,
PortsOrch *portOrch, RouteOrch *routeOrch, NeighOrch *neighOrch, FdbOrch *fdbOrch, PolicerOrch *policerOrch);

bool bake() override;
bool postBake() override;
void update(SubjectType, void *);
bool sessionExists(const string&);
bool getSessionStatus(const string&, bool&);
Expand All @@ -86,6 +88,10 @@ class MirrorOrch : public Orch, public Observer, public Subject
Table m_mirrorTable;

MirrorTable m_syncdMirrors;
// session_name -> VLAN : monitor_port_alias
map<string, string> m_recoverySessionPortMap;

bool m_freezeUpdate = false;

void createEntry(const string&, const vector<FieldValueTuple>&);
void deleteEntry(const string&);
Expand Down
16 changes: 16 additions & 0 deletions orchagent/neighorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,22 @@ bool NeighOrch::getNeighborEntry(const IpAddress &ipAddress, NeighborEntry &neig
return false;
}

bool NeighOrch::getNeighborEntry(const string &interface, NeighborEntry &neighborEntry, MacAddress &macAddress)
{
for (const auto &entry : m_syncdNeighbors)
{
if (entry.first.alias == interface)
{
neighborEntry = entry.first;
macAddress = entry.second;
return true;
}
}

return false;
}


void NeighOrch::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();
Expand Down
1 change: 1 addition & 0 deletions orchagent/neighorch.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class NeighOrch : public Orch, public Subject
void decreaseNextHopRefCount(const IpAddress&);

bool getNeighborEntry(const IpAddress&, NeighborEntry&, MacAddress&);
bool getNeighborEntry(const string&, NeighborEntry&, MacAddress&);

bool ifChangeInformNextHop(const string &, bool);
bool isNextHopFlagSet(const IpAddress &, const uint32_t);
Expand Down
Loading

0 comments on commit 29b4999

Please sign in to comment.