forked from stratum/stratum
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathonlp_phal_cli.cc
181 lines (159 loc) · 5.75 KB
/
onlp_phal_cli.cc
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
// Copyright 2018 Google LLC
// Copyright 2018-present Open Networking Foundation
// SPDX-License-Identifier: Apache-2.0
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "absl/strings/str_split.h"
#include "absl/time/clock.h"
#include "absl/time/time.h"
#include "gflags/gflags.h"
#include "re2/re2.h"
#include "stratum/glue/init_google.h"
#include "stratum/glue/status/status.h"
#include "stratum/glue/status/status_macros.h"
#include "stratum/glue/status/statusor.h"
#include "stratum/hal/lib/phal/attribute_database.h"
#include "stratum/hal/lib/phal/attribute_database_interface.h"
#include "stratum/hal/lib/phal/onlp/onlp_phal.h"
#include "stratum/hal/lib/phal/onlp/onlp_switch_configurator.h"
#include "stratum/lib/macros.h"
namespace stratum {
namespace hal {
namespace phal {
namespace onlp {
// Handles various CLI interactions with an attribute database.
class OnlpPhalCli {
public:
// All CLI queries are run on the given attribute database.
explicit OnlpPhalCli(OnlpPhal* onlpphal) : onlpphal_(onlpphal) {}
// Reads the given string into a PHAL query. Returns a failure if the given
// string uses invalid syntax. This does not guarantee that it is a valid path
// into the PHAL database.
//
// The given string should consiste of at least one '/' separated field. Each
// field is an attribute group or attribute name followed by an optional
// index. The index is bracketed, and consists of either a non-negative
// integer or '@' indicating all indices. The last field may optionally end
// with a '/' to indicate a terminal group.
//
// Valid examples:
// "foo/bar[1]/attr"
// "foo/bar[@]/attr"
// "foo/bar[1]/" (query everything under bar[1])
//
// Invalid examples:
// "/" (at least one field is required)
// "foo//bar"
// "foo/bar[-1]/"
::util::StatusOr<Path> ParseQuery(const std::string& query) {
std::vector<std::string> query_fields = absl::StrSplit(query, "/");
bool use_terminal_group = false;
if (query_fields[query_fields.size() - 1] == "") {
use_terminal_group = true; // Query ends with a '/'
query_fields = {query_fields.begin(),
query_fields.begin() + query_fields.size() - 1};
}
Path query_path;
for (const auto& query_field : query_fields) {
RET_CHECK(query_field != "")
<< "Encountered unexpected empty query field.";
RE2 field_regex(R"#((\w+)(\[(?:\d+|\@)\])?)#");
RE2 bracket_regex(R"#(\[(\d+)\])#");
PathEntry entry;
std::string bracket_match;
RET_CHECK(
RE2::FullMatch(query_field, field_regex, &entry.name, &bracket_match))
<< "Could not parse query field: " << query_field;
if (!bracket_match.empty()) {
entry.indexed = true;
if (!RE2::FullMatch(bracket_match, bracket_regex, &entry.index))
entry.all = true;
}
query_path.push_back(entry);
}
query_path[query_path.size() - 1].terminal_group = use_terminal_group;
return query_path;
}
// Queries the given path into the PHAL attribute database and prints the
// result to std::cout. Also prints timing stats for generating and executing
// the query. Only returns failure if the given query path does not match the
// database schema.
::util::Status HandleQuery(const Path& path) {
absl::Time start_time = absl::Now();
ASSIGN_OR_RETURN(auto db_query, onlpphal_->database_->MakeQuery({path}));
absl::Time generate_time = absl::Now();
ASSIGN_OR_RETURN(auto result, db_query->Get());
absl::Time execute_time = absl::Now();
int generate_duration =
(generate_time - start_time) / absl::Microseconds(1);
int execute_duration =
(execute_time - generate_time) / absl::Microseconds(1);
auto result_str = result->DebugString();
if (result_str.size() <= 0) {
std::cout << "No Results" << std::endl;
} else {
std::cout << result_str << std::endl;
}
std::cout << "Generated query in " << generate_duration << " us."
<< std::endl;
std::cout << "Executed query in " << execute_duration << " us."
<< std::endl;
return ::util::OkStatus();
}
// Runs the main CLI loop.
::util::Status RunCli() {
while (true) { // Grap input from std::cin and pass it to a OnlpPhalCli.
std::string query;
std::cout << "Enter a PHAL path: ";
std::getline(std::cin, query);
if (std::cin.eof()) break;
if (query == "") {
std::cout << "Use ^D to quit." << std::endl;
} else {
::util::StatusOr<Path> path = ParseQuery(query);
if (!path.ok()) {
std::cerr << "ERROR: Failed to generate query: " << path.status();
continue;
}
::util::Status result = HandleQuery(path.ValueOrDie());
if (!result.ok()) {
std::cerr << "ERROR: Failed to execute query (this is a bug!): "
<< result;
continue;
}
}
}
std::cout << "Exiting." << std::endl;
return ::util::OkStatus();
}
private:
const OnlpPhal* onlpphal_;
};
::util::Status Main(int argc, char** argv) {
InitGoogle("onlpphal_cli --phal_config_file <config_path>", &argc, &argv,
true);
stratum::InitStratumLogging();
// Need to init Onlp Interface
auto onlp_wrapper = OnlpWrapper::CreateSingleton();
auto onlpphal = OnlpPhal::CreateSingleton(onlp_wrapper);
OnlpPhalCli cli(onlpphal);
cli.RunCli();
// Shutdown the ONLP Phal
onlpphal->Shutdown();
return ::util::OkStatus();
}
} // namespace onlp
} // namespace phal
} // namespace hal
} // namespace stratum
int main(int argc, char** argv) {
::util::Status status = stratum::hal::phal::onlp::Main(argc, argv);
if (status.ok()) {
return 0;
} else {
LOG(ERROR) << status;
return 1;
}
}