Skip to content

Commit eae91a2

Browse files
authored
[Dash] Update ENI Based Forwarding Orchagent (sonic-net#3905)
What I did Support FNIC pipeline changes for DashEniFwd Orch (No match on Tunnel VNI and only match on INNER_DST_MAC) Update DashEniFwdOrch to handle the updated schema for DPU, VDPU, REMOTE_DPU & DASH_ENI_FORWARD_TABLE Delete the ACL Table if all the ENI acl rules are deleted While creating Tunnel NH, also pass VNI. Update Aclorch to accept Tunnel NH in the following format: endpoint_ip@tunnel_name[,vni][,mac] Simplify the logic by removing the reference counting logic for Remote NH Tunnel tracking Added REQ_T_STRING_LIST option to Request parser Allow Relaxed Attribute parsing to Request parser This is needed because the Request parser expects a strict schema of field-value pairs.
1 parent 48e28b6 commit eae91a2

10 files changed

Lines changed: 865 additions & 642 deletions

orchagent/aclorch.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <limits.h>
33
#include <unordered_map>
44
#include <algorithm>
5+
#include <sstream>
56
#include "aclorch.h"
67
#include "logger.h"
78
#include "schema.h"
@@ -641,15 +642,37 @@ void AclRule::TunnelNH::load(const std::string& target)
641642

642643
void AclRule::TunnelNH::parse(const std::string& target)
643644
{
644-
/* Supported Format: endpoint_ip@tunnel_name */
645+
/* Expected Format: endpoint_ip@tunnel_name[,vni][,mac] */
645646
auto at_pos = target.find('@');
646647
if (at_pos == std::string::npos)
647648
{
648649
throw std::logic_error("Invalid format for Tunnel Next Hop");
649650
}
650651

651652
endpoint_ip = swss::IpAddress(target.substr(0, at_pos));
652-
tunnel_name = target.substr(at_pos + 1);
653+
std::stringstream ss(target.substr(at_pos + 1));
654+
655+
vector<string> components;
656+
while (ss.good())
657+
{
658+
std::string substr;
659+
getline(ss, substr, ',');
660+
components.push_back(substr);
661+
}
662+
if (components.empty())
663+
{
664+
throw std::logic_error("Invalid format for Tunnel Next Hop");
665+
}
666+
667+
tunnel_name = components[0];
668+
if (components.size() >= 2)
669+
{
670+
vni = static_cast<uint32_t>(std::stoul(components[1]));
671+
}
672+
if (components.size() == 3)
673+
{
674+
mac = swss::MacAddress(components[2]);
675+
}
653676
}
654677

655678
void AclRule::TunnelNH::clear()

orchagent/dash/dashenifwdinfo.cpp

Lines changed: 40 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ using namespace swss;
44
using namespace std;
55

66
const int EniAclRule::BASE_PRIORITY = 9996;
7-
const vector<string> EniAclRule::RULE_NAMES = {
8-
"IN",
9-
"OUT",
10-
"IN_TERM",
11-
"OUT_TERM"
12-
};
137

148
unique_ptr<EniNH> EniNH::createNextHop(dpu_type_t type, const IpAddress& ip)
159
{
@@ -55,30 +49,33 @@ void RemoteEniNH::resolve(EniInfo& eni)
5549
return ;
5650
}
5751

58-
if (ctx->handleTunnelNH(tunnel_name_, endpoint_, true))
59-
{
60-
setStatus(endpoint_status_t::RESOLVED);
61-
}
62-
else
52+
uint64_t vnet_vni;
53+
if (!ctx->findVnetVni(vnet, vnet_vni))
6354
{
55+
SWSS_LOG_ERROR("Couldn't find VNI for Vnet %s", vnet.c_str());
6456
setStatus(endpoint_status_t::UNRESOLVED);
57+
return ;
6558
}
66-
}
6759

68-
void RemoteEniNH::destroy(EniInfo& eni)
69-
{
70-
auto& ctx = eni.getCtx();
71-
ctx->handleTunnelNH(tunnel_name_, endpoint_, false);
60+
vni_ = std::to_string(vnet_vni);
61+
62+
/* Note: AclOrch already has logic to create / delete Tunnel NH, no need to create here */
63+
setStatus(endpoint_status_t::RESOLVED);
7264
}
7365

7466
string RemoteEniNH::getRedirectVal()
7567
{
76-
return endpoint_.to_string() + "@" + tunnel_name_;
68+
/* Format Expected by AclOrch: endpoint_ip@tunnel_name[,vni][,mac] */
69+
return endpoint_.to_string() + "@" + tunnel_name_ + ',' + vni_;
7770
}
7871

7972
void EniAclRule::setKey(EniInfo& eni)
8073
{
81-
name_ = string(ENI_REDIRECT_TABLE) + ":" + eni.toKey() + "_" + EniAclRule::RULE_NAMES[type_];
74+
name_ = string(DashEniFwd::TABLE) + ":" + eni.toKey();
75+
if (type_ == rule_type_t::TUNNEL_TERM)
76+
{
77+
name_ += "_TERM";
78+
}
8279
}
8380

8481
update_type_t EniAclRule::processUpdate(EniInfo& eni)
@@ -88,9 +85,9 @@ update_type_t EniAclRule::processUpdate(EniInfo& eni)
8885
IpAddress primary_endp;
8986
dpu_type_t primary_type = LOCAL;
9087
update_type_t update_type = PRIMARY_UPDATE;
91-
uint64_t primary_id;
88+
std::string primary_id;
9289

93-
if (type_ == rule_type_t::INBOUND_TERM || type_ == rule_type_t::OUTBOUND_TERM)
90+
if (type_ == rule_type_t::TUNNEL_TERM)
9491
{
9592
/* Tunnel term entries always use local endpoint regardless of primary id */
9693
if (!eni.findLocalEp(primary_id))
@@ -106,7 +103,7 @@ update_type_t EniAclRule::processUpdate(EniInfo& eni)
106103

107104
if (!ctx->dpu_info.getType(primary_id, primary_type))
108105
{
109-
SWSS_LOG_ERROR("No primaryId in DPU Table %" PRIu64 "", primary_id);
106+
SWSS_LOG_ERROR("No primary id %s in DPU Table", primary_id.c_str());
110107
return update_type_t::INVALID;
111108
}
112109

@@ -182,9 +179,8 @@ void EniAclRule::fire(EniInfo& eni)
182179
Delete the complete rule before updating it,
183180
ACLOrch Doesn't support incremental updates
184181
*/
185-
ctx->rule_table->del(key);
182+
ctx->deleteAclRule(key);
186183
setState(rule_state_t::UNINSTALLED);
187-
SWSS_LOG_NOTICE("EniFwd ACL Rule %s deleted", key.c_str());
188184
}
189185

190186
if (nh_->getStatus() != endpoint_status_t::RESOLVED)
@@ -201,27 +197,17 @@ void EniAclRule::fire(EniInfo& eni)
201197
{ ACTION_REDIRECT_ACTION, nh_->getRedirectVal() }
202198
};
203199

204-
if (type_ == rule_type_t::INBOUND_TERM || type_ == rule_type_t::OUTBOUND_TERM)
200+
if (type_ == rule_type_t::TUNNEL_TERM)
205201
{
206202
fv_.push_back({MATCH_TUNNEL_TERM, "true"});
207203
}
208-
209-
if (type_ == rule_type_t::OUTBOUND || type_ == rule_type_t::OUTBOUND_TERM)
210-
{
211-
fv_.push_back({MATCH_TUNNEL_VNI, to_string(eni.getOutVni())});
212-
}
213204

214-
ctx->rule_table->set(key, fv_);
205+
ctx->createAclRule(key, fv_);
215206
setState(INSTALLED);
216-
SWSS_LOG_NOTICE("EniFwd ACL Rule %s installed", key.c_str());
217207
}
218208

219209
string EniAclRule::getMacMatchDirection(EniInfo& eni)
220210
{
221-
if (type_ == OUTBOUND || type_ == OUTBOUND_TERM)
222-
{
223-
return eni.getOutMacLookup();
224-
}
225211
return MATCH_INNER_DST_MAC;
226212
}
227213

@@ -231,7 +217,7 @@ void EniAclRule::destroy(EniInfo& eni)
231217
{
232218
auto key = getKey();
233219
auto& ctx = eni.getCtx();
234-
ctx->rule_table->del(key);
220+
ctx->deleteAclRule(key);
235221
if (nh_ != nullptr)
236222
{
237223
nh_->destroy(eni);
@@ -292,10 +278,8 @@ bool EniInfo::create(const Request& db_request)
292278
SWSS_LOG_ENTER();
293279

294280
auto updates = db_request.getAttrFieldNames();
295-
auto itr_ep_list = updates.find(ENI_FWD_VDPU_IDS);
296-
auto itr_primary_id = updates.find(ENI_FWD_PRIMARY);
297-
auto itr_out_vni = updates.find(ENI_FWD_OUT_VNI);
298-
auto itr_out_mac_dir = updates.find(ENI_FWD_OUT_MAC_LOOKUP);
281+
auto itr_ep_list = updates.find(DashEniFwd::VDPU_IDS);
282+
auto itr_primary_id = updates.find(DashEniFwd::PRIMARY);
299283

300284
/* Validation Checks */
301285
if (itr_ep_list == updates.end() || itr_primary_id == updates.end())
@@ -304,85 +288,26 @@ bool EniInfo::create(const Request& db_request)
304288
return false;
305289
}
306290

307-
ep_list_ = db_request.getAttrUintList(ENI_FWD_VDPU_IDS);
308-
primary_id_ = db_request.getAttrUint(ENI_FWD_PRIMARY);
291+
ep_list_ = db_request.getAttrStringList(DashEniFwd::VDPU_IDS);
292+
primary_id_ = db_request.getAttrString(DashEniFwd::PRIMARY);
309293

310-
uint64_t local_id;
294+
std::string local_id;
311295
bool tunn_term_allow = findLocalEp(local_id);
312-
bool outbound_allow = false;
313296

314297
/* Create Rules */
315298
rule_container_.emplace(piecewise_construct,
316-
forward_as_tuple(rule_type_t::INBOUND),
317-
forward_as_tuple(rule_type_t::INBOUND, *this));
318-
rule_container_.emplace(piecewise_construct,
319-
forward_as_tuple(rule_type_t::OUTBOUND),
320-
forward_as_tuple(rule_type_t::OUTBOUND, *this));
299+
forward_as_tuple(rule_type_t::NO_TUNNEL_TERM),
300+
forward_as_tuple(rule_type_t::NO_TUNNEL_TERM, *this));
321301

322302
if (tunn_term_allow)
323303
{
324-
/* Create rules for tunnel termination if required */
325-
rule_container_.emplace(piecewise_construct,
326-
forward_as_tuple(rule_type_t::INBOUND_TERM),
327-
forward_as_tuple(rule_type_t::INBOUND_TERM, *this));
304+
/* Create rule for tunnel termination if required */
328305
rule_container_.emplace(piecewise_construct,
329-
forward_as_tuple(rule_type_t::OUTBOUND_TERM),
330-
forward_as_tuple(rule_type_t::OUTBOUND_TERM, *this));
331-
}
332-
333-
/* Infer Direction to check MAC for outbound rules */
334-
if (itr_out_mac_dir == updates.end())
335-
{
336-
outbound_mac_lookup_ = MATCH_INNER_SRC_MAC;
337-
}
338-
else
339-
{
340-
auto str = db_request.getAttrString(ENI_FWD_OUT_MAC_LOOKUP);
341-
if (str == OUT_MAC_DIR)
342-
{
343-
outbound_mac_lookup_ = MATCH_INNER_DST_MAC;
344-
}
345-
else
346-
{
347-
outbound_mac_lookup_ = MATCH_INNER_SRC_MAC;
348-
}
349-
}
350-
351-
/* Infer tunnel_vni for the outbound rules */
352-
if (itr_out_vni == updates.end())
353-
{
354-
if (ctx->findVnetVni(vnet_name_, outbound_vni_))
355-
{
356-
outbound_allow = true;
357-
}
358-
else
359-
{
360-
SWSS_LOG_ERROR("Invalid VNET: No VNI. Cannot install outbound rules: %s", toKey().c_str());
361-
}
362-
}
363-
else
364-
{
365-
outbound_vni_ = db_request.getAttrUint(ENI_FWD_OUT_VNI);
366-
outbound_allow = true;
367-
}
368-
369-
fireRule(rule_type_t::INBOUND);
370-
371-
if (tunn_term_allow)
372-
{
373-
fireRule(rule_type_t::INBOUND_TERM);
374-
}
375-
376-
if (outbound_allow)
377-
{
378-
fireRule(rule_type_t::OUTBOUND);
379-
}
380-
381-
if (tunn_term_allow && outbound_allow)
382-
{
383-
fireRule(rule_type_t::OUTBOUND_TERM);
306+
forward_as_tuple(rule_type_t::TUNNEL_TERM),
307+
forward_as_tuple(rule_type_t::TUNNEL_TERM, *this));
384308
}
385309

310+
fireAllRules();
386311
return true;
387312
}
388313

@@ -408,34 +333,34 @@ bool EniInfo::update(const Request& db_request)
408333

409334
/* Only primary_id is expected to change after ENI is created */
410335
auto updates = db_request.getAttrFieldNames();
411-
auto itr_primary_id = updates.find(ENI_FWD_PRIMARY);
336+
auto itr_primary_id = updates.find(DashEniFwd::PRIMARY);
412337

413338
/* Validation Checks */
414339
if (itr_primary_id == updates.end())
415340
{
416341
throw logic_error("Invalid DASH_ENI_FORWARD_TABLE update: No primary idx");
417342
}
418343

419-
if (getPrimaryId() == db_request.getAttrUint(ENI_FWD_PRIMARY))
344+
if (getPrimaryId() == db_request.getAttrString(DashEniFwd::PRIMARY))
420345
{
421346
/* No update in the primary id, return true */
422347
return true;
423348
}
424349

425350
/* Update local primary id and fire the rules */
426-
primary_id_ = db_request.getAttrUint(ENI_FWD_PRIMARY);
351+
primary_id_ = db_request.getAttrString(DashEniFwd::PRIMARY);
427352
fireAllRules();
428353

429354
return true;
430355
}
431356

432-
bool EniInfo::findLocalEp(uint64_t& local_endpoint) const
357+
bool EniInfo::findLocalEp(std::string& local_endpoint) const
433358
{
434359
/* Check if atleast one of the endpoints is local */
435360
bool found = false;
436361
for (auto idx : ep_list_)
437362
{
438-
dpu_type_t val = dpu_type_t::EXTERNAL;
363+
dpu_type_t val = dpu_type_t::CLUSTER;
439364
if (ctx->dpu_info.getType(idx, val) && val == dpu_type_t::LOCAL)
440365
{
441366
if (!found)
@@ -445,8 +370,8 @@ bool EniInfo::findLocalEp(uint64_t& local_endpoint) const
445370
}
446371
else
447372
{
448-
SWSS_LOG_WARN("Multiple Local Endpoints for the ENI %s found, proceeding with %" PRIu64 "" ,
449-
mac_.to_string().c_str(), local_endpoint);
373+
SWSS_LOG_WARN("Multiple Local Endpoints for the ENI %s found, proceeding with %s",
374+
mac_.to_string().c_str(), local_endpoint.c_str());
450375
}
451376
}
452377
}

0 commit comments

Comments
 (0)