Skip to content

Commit c4d61f8

Browse files
NOS-6649..NOS-6656: fboss2 bgp policy community-list community subcommand
1 parent c85ed80 commit c4d61f8

9 files changed

Lines changed: 735 additions & 0 deletions

File tree

cmake/CliFboss2.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,8 @@ add_library(fboss2_config_lib
890890
fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/BgpCommunityListCliUtils.h
891891
fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.cpp
892892
fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.h
893+
fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.cpp
894+
fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.h
893895
fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.cpp
894896
fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h
895897
fboss/cli/fboss2/commands/config/ptp/transparent_clock/CmdConfigPtpTransparentClock.cpp

fboss/cli/fboss2/BUCK

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,7 @@ cpp_library(
11041104
"commands/config/protocol/bgp/policy/as-path-list/CmdConfigProtocolBgpPolicyAsPathList.cpp",
11051105
"commands/config/protocol/bgp/policy/as-path-list/entry/CmdConfigProtocolBgpPolicyAsPathListEntry.cpp",
11061106
"commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.cpp",
1107+
"commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.cpp",
11071108
"commands/config/protocol/static/CmdConfigProtocolStatic.cpp",
11081109
"commands/config/protocol/static/route/add/CmdConfigProtocolStaticRouteAdd.cpp",
11091110
"commands/config/ptp/CmdConfigPtp.cpp",
@@ -1220,6 +1221,7 @@ cpp_library(
12201221
"commands/config/protocol/bgp/policy/as-path-list/entry/CmdConfigProtocolBgpPolicyAsPathListEntry.h",
12211222
"commands/config/protocol/bgp/policy/community-list/BgpCommunityListCliUtils.h",
12221223
"commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.h",
1224+
"commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.h",
12231225
"commands/config/protocol/static/CmdConfigProtocolStatic.h",
12241226
"commands/config/protocol/static/route/StaticRouteUtils.h",
12251227
"commands/config/protocol/static/route/add/CmdConfigProtocolStaticRouteAdd.h",

fboss/cli/fboss2/CmdListConfig.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/as-path-list/CmdConfigProtocolBgpPolicyAsPathList.h"
4545
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/as-path-list/entry/CmdConfigProtocolBgpPolicyAsPathListEntry.h"
4646
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.h"
47+
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.h"
4748
#include "fboss/cli/fboss2/commands/config/protocol/static/CmdConfigProtocolStatic.h"
4849
#include "fboss/cli/fboss2/commands/config/protocol/static/route/add/CmdConfigProtocolStaticRouteAdd.h"
4950
#include "fboss/cli/fboss2/commands/config/ptp/CmdConfigPtp.h"
@@ -418,6 +419,16 @@ const CommandTree& kConfigCommandTree() {
418419
CmdConfigProtocolBgpPolicyCommunityList>,
419420
argRegistrar<
420421
CmdConfigProtocolBgpPolicyCommunityListTraits>,
422+
{{
423+
"community",
424+
"Configure a community-list community: "
425+
"<name> [<attribute> <value> ...] "
426+
"(description, type, value)",
427+
commandHandler<
428+
CmdConfigProtocolBgpPolicyCommunityListCommunity>,
429+
argRegistrar<
430+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits>,
431+
}},
421432
}},
422433
},
423434
},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
/*
2+
* Copyright (c) 2004-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/community/CmdConfigProtocolBgpPolicyCommunityListCommunity.h"
12+
13+
#include "fboss/cli/fboss2/CmdHandler.cpp"
14+
15+
#include <fmt/core.h>
16+
#include <neteng/fboss/bgp/public_tld/configerator/structs/neteng/fboss/bgp/gen-cpp2/bgp_config_types.h>
17+
#include <iostream>
18+
#include <map>
19+
#include <optional>
20+
#include <ostream>
21+
#include <stdexcept>
22+
#include <string>
23+
#include <string_view>
24+
#include <vector>
25+
#include "configerator/structs/neteng/bgp_policy/thrift/gen-cpp2/bgp_policy_types.h"
26+
#include "fboss/cli/fboss2/commands/config/protocol/bgp/BgpCliAttrHandlers.h"
27+
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/BgpCommunityListCliUtils.h"
28+
#include "fboss/cli/fboss2/session/ConfigSession.h"
29+
#include "fboss/cli/fboss2/utils/CmdUtilsCommon.h"
30+
#include "fboss/cli/fboss2/utils/HostInfo.h"
31+
#include "fmt/format.h"
32+
33+
namespace facebook::fboss {
34+
35+
namespace {
36+
37+
// The attribute names, exactly as documented. Kept here so the
38+
// valid-attribute set and the handler table stay in sync.
39+
constexpr std::string_view kDescription = "description";
40+
constexpr std::string_view kType = "type";
41+
constexpr std::string_view kValue = "value";
42+
43+
// type values (bgp_policy.CommunityType names).
44+
constexpr std::string_view kCommunityTypeNormal = "NORMAL";
45+
constexpr std::string_view kCommunityTypeExtended = "EXTENDED";
46+
constexpr std::string_view kCommunityTypeLarge = "LARGE";
47+
48+
using Community = bgp::bgp_policy::Community;
49+
using CommunityType = bgp::bgp_policy::CommunityType;
50+
using bgpcli::AttrHandler;
51+
using bgpcli::enumAttr;
52+
using bgpcli::joinedStringAttr;
53+
using bgpcli::ok;
54+
using bgpcli::Result;
55+
using bgpcli::stringAttr;
56+
57+
// ---- value lookups ----------------------------------------------------------
58+
59+
std::optional<CommunityType> lookupCommunityType(const std::string& s) {
60+
if (s == kCommunityTypeNormal) {
61+
return CommunityType::NORMAL;
62+
}
63+
if (s == kCommunityTypeExtended) {
64+
return CommunityType::EXTENDED;
65+
}
66+
if (s == kCommunityTypeLarge) {
67+
return CommunityType::LARGE;
68+
}
69+
return std::nullopt;
70+
}
71+
72+
// ---- community-level setters ------------------------------------------------
73+
// Each writes one already-parsed, already-validated value. Parsing and message
74+
// text belong to the shared factories in BgpCliAttrHandlers.h.
75+
76+
void setDescription(Community& community, const std::string& description) {
77+
community.description() = description;
78+
}
79+
80+
void setType(Community& community, CommunityType type) {
81+
community.type() = type;
82+
}
83+
84+
void setValue(Community& community, const std::string& value) {
85+
community.value() = value;
86+
}
87+
88+
// ---- community-level attribute registry -------------------------------------
89+
// One line per documented attribute: its dispatch key, its value shape, and
90+
// the setter that stores it.
91+
const std::map<std::string, AttrHandler<Community>, std::less<>>&
92+
communityAttrHandlers() {
93+
static const std::string kCommunityTypeValues = fmt::format(
94+
"{}|{}|{}",
95+
kCommunityTypeNormal,
96+
kCommunityTypeExtended,
97+
kCommunityTypeLarge);
98+
static const std::map<std::string, AttrHandler<Community>, std::less<>>
99+
kHandlers = {
100+
{std::string(kDescription),
101+
joinedStringAttr<Community>(kDescription, setDescription)},
102+
{std::string(kType),
103+
enumAttr<Community, CommunityType>(
104+
kType, kCommunityTypeValues, lookupCommunityType, setType)},
105+
{std::string(kValue),
106+
stringAttr<Community>(kValue, "string", setValue)},
107+
};
108+
return kHandlers;
109+
}
110+
111+
std::string validAttrList() {
112+
std::string out;
113+
for (const auto& [name, _] : communityAttrHandlers()) {
114+
if (!out.empty()) {
115+
out += ", ";
116+
}
117+
out += name;
118+
}
119+
return out;
120+
}
121+
122+
} // namespace
123+
124+
// Parse + validate at construction so queryClient stays a thin dispatch.
125+
// Throwing std::invalid_argument is how the framework surfaces arg parse
126+
// errors (same mechanism as BgpCommunityListConfig).
127+
BgpCommunityListCommunityConfig::BgpCommunityListCommunityConfig(
128+
std::vector<std::string> v)
129+
: utils::BaseObjectArgType<std::string>(v) {
130+
if (v.empty() || v[0].empty()) {
131+
throw std::invalid_argument(
132+
"Error: community <name> is required, optionally followed by an "
133+
"<attribute> <value>");
134+
}
135+
communityName_ = v[0];
136+
if (v.size() == 1) {
137+
return; // bare `community <name>`: create it
138+
}
139+
140+
attr_ = v[1];
141+
values_.assign(v.begin() + 2, v.end());
142+
143+
if (communityAttrHandlers().find(attr_) == communityAttrHandlers().end()) {
144+
throw std::invalid_argument(
145+
fmt::format(
146+
"Error: unknown community-list community attribute '{}'. Valid "
147+
"attributes: {}",
148+
attr_,
149+
validAttrList()));
150+
}
151+
}
152+
153+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits::RetType
154+
CmdConfigProtocolBgpPolicyCommunityListCommunity::queryClient(
155+
const HostInfo& /* hostInfo */,
156+
const BgpCommunityListConfig& listArgs,
157+
const ObjectArgType& args) {
158+
// The parent parse accepts `community-list <name> <attr> <value> ...
159+
// community ...`, but only the leaf (this command) runs — silently dropping
160+
// the list-level attribute would look like it was staged. Reject the mix.
161+
if (!listArgs.attr().empty()) {
162+
return fmt::format(
163+
"Error: configure community-list attributes and community in separate "
164+
"commands (got community-list attribute '{}' alongside community {})",
165+
listArgs.attr(),
166+
args.communityName());
167+
}
168+
169+
auto& session = ConfigSession::getInstance();
170+
auto& cfg = session.getBgpConfig();
171+
const bool listCreated =
172+
!bgpcli::communityListExists(cfg, listArgs.listName());
173+
auto& list = bgpcli::findOrCreateCommunityList(cfg, listArgs.listName());
174+
const bool hadMembers = list.members().has_value();
175+
const bool memberCreated =
176+
!bgpcli::communityMemberExists(list, args.communityName());
177+
auto& community =
178+
bgpcli::findOrCreateCommunityMember(list, args.communityName());
179+
180+
Result result = args.attr().empty()
181+
? ok(memberCreated
182+
? fmt::format(
183+
"Successfully created BGP community-list {} community {}",
184+
listArgs.listName(),
185+
args.communityName())
186+
: fmt::format(
187+
"BGP community-list {} community {} already exists",
188+
listArgs.listName(),
189+
args.communityName()))
190+
// The attribute is guaranteed valid: BgpCommunityListCommunityConfig's
191+
// constructor rejects an unknown attribute before we get here.
192+
: communityAttrHandlers()
193+
.find(args.attr())
194+
->second(community, args.values());
195+
196+
if (result.ok) {
197+
if (!args.attr().empty()) {
198+
result.message += fmt::format(
199+
" for community-list {} community {}",
200+
listArgs.listName(),
201+
args.communityName());
202+
}
203+
session.saveBgpConfig();
204+
result.message +=
205+
fmt::format("\nConfig saved to: {}", session.getBgpSessionConfigPath());
206+
} else {
207+
// A rejected value must not leave a phantom member (or a phantom list
208+
// implicitly created for it) visible to later lookups in this process —
209+
// restoring an unset members field if this invocation ensured it.
210+
if (memberCreated) {
211+
if (hadMembers) {
212+
list.members()->pop_back();
213+
} else {
214+
list.members().reset();
215+
}
216+
}
217+
if (listCreated) {
218+
cfg.policies()->community_lists()->pop_back();
219+
}
220+
}
221+
return result.message;
222+
}
223+
224+
void CmdConfigProtocolBgpPolicyCommunityListCommunity::printOutput(
225+
const RetType& output) {
226+
std::cout << output << std::endl;
227+
}
228+
229+
// Explicit template instantiation
230+
template void CmdHandler<
231+
CmdConfigProtocolBgpPolicyCommunityListCommunity,
232+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits>::run();
233+
234+
} // namespace facebook::fboss
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* Copyright (c) 2004-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#pragma once
12+
13+
#include <string>
14+
#include <vector>
15+
#include "CLI/App.hpp"
16+
#include "fboss/cli/fboss2/CmdHandler.h"
17+
#include "fboss/cli/fboss2/commands/config/protocol/bgp/policy/community-list/CmdConfigProtocolBgpPolicyCommunityList.h"
18+
#include "fboss/cli/fboss2/utils/CmdUtilsCommon.h"
19+
#include "fboss/cli/fboss2/utils/HostInfo.h"
20+
21+
namespace facebook::fboss {
22+
23+
// Parsed `community <name> [<attribute> <value> ...]`, validated at
24+
// construction. A member (bgp_policy.Community, held inline through the
25+
// CommunityRefType union's `community` arm in CommunityList.members[]) is
26+
// keyed by <name>; the list it belongs to is supplied by the parent command's
27+
// args.
28+
//
29+
// Grammar (from the FBOSS proposed syntax):
30+
// ... community-list <name> community <name> (create/select)
31+
// ... community-list <name> community <name> description <string>
32+
// ... community-list <name> community <name> type <type>
33+
// ... community-list <name> community <name> value <string>
34+
class BgpCommunityListCommunityConfig
35+
: public utils::BaseObjectArgType<std::string> {
36+
public:
37+
// NOLINTNEXTLINE(google-explicit-constructor)
38+
/* implicit */ BgpCommunityListCommunityConfig(std::vector<std::string> v);
39+
const std::string& communityName() const {
40+
return communityName_;
41+
}
42+
const std::string& attr() const {
43+
return attr_;
44+
}
45+
const std::vector<std::string>& values() const {
46+
return values_;
47+
}
48+
const static utils::ObjectArgTypeId id =
49+
utils::ObjectArgTypeId::OBJECT_ARG_TYPE_ID_MESSAGE;
50+
51+
private:
52+
std::string communityName_;
53+
std::string attr_; // matched dispatch key ("" = bare create)
54+
std::vector<std::string> values_;
55+
};
56+
57+
// The community (member) level of the community-list family as its own CLI11
58+
// subcommand; the parent's parsed args arrive through the ancestor-args tuple,
59+
// mirroring CmdConfigProtocolBgpPolicyAsPathListEntry.
60+
struct CmdConfigProtocolBgpPolicyCommunityListCommunityTraits
61+
: public WriteCommandTraits {
62+
using ParentCmd = CmdConfigProtocolBgpPolicyCommunityList;
63+
static void addCliArg(CLI::App& cmd, std::vector<std::string>& args) {
64+
// Community has no nested subcommands; stop CLI11's parent-chain
65+
// fallthrough from stealing a value token that spells `community`.
66+
cmd.positionals_at_end();
67+
cmd.add_option("args", args, "<name> [<attribute> <value> ...]");
68+
}
69+
using ObjectArgType = BgpCommunityListCommunityConfig;
70+
using RetType = std::string;
71+
};
72+
73+
class CmdConfigProtocolBgpPolicyCommunityListCommunity
74+
: public CmdHandler<
75+
CmdConfigProtocolBgpPolicyCommunityListCommunity,
76+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits> {
77+
public:
78+
using ObjectArgType =
79+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits::ObjectArgType;
80+
using RetType =
81+
CmdConfigProtocolBgpPolicyCommunityListCommunityTraits::RetType;
82+
83+
RetType queryClient(
84+
const HostInfo& hostInfo,
85+
const BgpCommunityListConfig& listArgs,
86+
const ObjectArgType& args);
87+
88+
void printOutput(const RetType& output);
89+
};
90+
91+
} // namespace facebook::fboss

fboss/cli/fboss2/test/config/BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ cpp_unittest(
1515
"CmdConfigBgpPeerGroupTest.cpp",
1616
"CmdConfigBgpPolicyAsPathListEntryTest.cpp",
1717
"CmdConfigBgpPolicyAsPathListTest.cpp",
18+
"CmdConfigBgpPolicyCommunityListCommunityTest.cpp",
1819
"CmdConfigBgpPolicyCommunityListTest.cpp",
1920
"CmdConfigCoppTest.cpp",
2021
"CmdConfigDhcpTest.cpp",

0 commit comments

Comments
 (0)