forked from stratum/stratum
-
Notifications
You must be signed in to change notification settings - Fork 7
/
dpdk_sde_target.cc
209 lines (174 loc) · 7.62 KB
/
dpdk_sde_target.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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Copyright 2019-present Barefoot Networks, Inc.
// Copyright 2022-2023 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
// DPDK-specific SDE wrapper methods.
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "absl/synchronization/mutex.h"
#include "stratum/glue/logging.h"
#include "stratum/glue/status/status.h"
#include "stratum/glue/status/statusor.h"
#include "stratum/hal/lib/tdi/macros.h"
#include "stratum/hal/lib/tdi/tdi_sde_common.h"
#include "stratum/hal/lib/tdi/tdi_sde_helpers.h"
#include "stratum/hal/lib/tdi/tdi_sde_wrapper.h"
#include "stratum/lib/utils.h"
extern "C" {
#include "bf_pal/dev_intf.h"
#include "bf_switchd/lib/bf_switchd_lib_init.h"
}
namespace stratum {
namespace hal {
namespace tdi {
using namespace stratum::hal::tdi::helpers;
::util::StatusOr<bool> TdiSdeWrapper::IsSoftwareModel(int device) {
return true;
}
std::string TdiSdeWrapper::GetChipType(int device) const { return "DPDK"; }
std::string TdiSdeWrapper::GetSdeVersion() const {
// TODO tdi version
return "1.0.0";
}
::util::Status TdiSdeWrapper::InitializeSde(const std::string& sde_install_path,
const std::string& sde_config_file,
bool run_in_background) {
CHECK_RETURN_IF_FALSE(sde_install_path != "")
<< "sde_install_path is required";
CHECK_RETURN_IF_FALSE(sde_config_file != "") << "sde_config_file is required";
// Parse bf_switchd arguments.
auto switchd_main_ctx = absl::make_unique<bf_switchd_context_t>();
switchd_main_ctx->install_dir = strdup(sde_install_path.c_str());
switchd_main_ctx->conf_file = strdup(sde_config_file.c_str());
switchd_main_ctx->skip_p4 = true;
if (run_in_background) {
switchd_main_ctx->running_in_background = true;
} else {
switchd_main_ctx->shell_set_ucli = true;
}
// Determine if kernel mode packet driver is loaded.
std::string bf_sysfs_fname;
{
char buf[128] = {};
RETURN_IF_TDI_ERROR(switch_pci_sysfs_str_get(buf, sizeof(buf)));
bf_sysfs_fname = buf;
}
absl::StrAppend(&bf_sysfs_fname, "/dev_add");
LOG(INFO) << "bf_sysfs_fname: " << bf_sysfs_fname;
if (PathExists(bf_sysfs_fname)) {
// Override previous parsing if bf_kpkt KLM was loaded.
LOG(INFO)
<< "kernel mode packet driver present, forcing kernel_pkt option!";
}
RETURN_IF_TDI_ERROR(bf_switchd_lib_init(switchd_main_ctx.get()))
<< "Error when starting switchd.";
LOG(INFO) << "switchd started successfully";
// Set SDE log levels for modules of interest.
// TODO(max): create story around SDE logs. How to get them into glog? What
// levels to enable for which modules?
CHECK_RETURN_IF_FALSE(
bf_sys_log_level_set(BF_MOD_BFRT, BF_LOG_DEST_STDOUT, BF_LOG_WARN) == 0);
CHECK_RETURN_IF_FALSE(
bf_sys_log_level_set(BF_MOD_PKT, BF_LOG_DEST_STDOUT, BF_LOG_WARN) == 0);
CHECK_RETURN_IF_FALSE(
bf_sys_log_level_set(BF_MOD_PIPE, BF_LOG_DEST_STDOUT, BF_LOG_WARN) == 0);
if (VLOG_IS_ON(2)) {
CHECK_RETURN_IF_FALSE(bf_sys_log_level_set(BF_MOD_PIPE, BF_LOG_DEST_STDOUT,
BF_LOG_WARN) == 0);
}
return ::util::OkStatus();
}
::util::Status TdiSdeWrapper::AddDevice(int dev_id,
const TdiDeviceConfig& device_config) {
const ::tdi::Device* device = nullptr;
absl::WriterMutexLock l(&data_lock_);
CHECK_RETURN_IF_FALSE(device_config.programs_size() > 0);
tdi_id_mapper_.reset();
RETURN_IF_TDI_ERROR(bf_pal_device_warm_init_begin(dev_id,
BF_DEV_WARM_INIT_FAST_RECFG,
/* upgrade_agents */ true));
bf_device_profile_t device_profile = {};
// Commit new files to disk and build device profile for SDE to load.
RETURN_IF_ERROR(RecursivelyCreateDir(FLAGS_tdi_sde_config_dir));
// Need to extend the lifetime of the path strings until the SDE reads them.
std::vector<std::unique_ptr<std::string>> path_strings;
device_profile.num_p4_programs = device_config.programs_size();
for (int i = 0; i < device_config.programs_size(); ++i) {
const auto& program = device_config.programs(i);
const std::string program_path =
absl::StrCat(FLAGS_tdi_sde_config_dir, "/", program.name());
auto tdi_path = absl::make_unique<std::string>(
absl::StrCat(program_path, "/bfrt.json"));
RETURN_IF_ERROR(RecursivelyCreateDir(program_path));
RETURN_IF_ERROR(WriteStringToFile(program.bfrt(), *tdi_path));
bf_p4_program_t* p4_program = &device_profile.p4_programs[i];
::snprintf(p4_program->prog_name, _PI_UPDATE_MAX_NAME_SIZE, "%s",
program.name().c_str());
p4_program->bfrt_json_file = &(*tdi_path)[0];
p4_program->num_p4_pipelines = program.pipelines_size();
path_strings.emplace_back(std::move(tdi_path));
CHECK_RETURN_IF_FALSE(program.pipelines_size() > 0);
for (int j = 0; j < program.pipelines_size(); ++j) {
const auto& pipeline = program.pipelines(j);
const std::string pipeline_path =
absl::StrCat(program_path, "/", pipeline.name());
auto context_path = absl::make_unique<std::string>(
absl::StrCat(pipeline_path, "/context.json"));
auto config_path = absl::make_unique<std::string>(
absl::StrCat(pipeline_path, "/tofino.bin"));
RETURN_IF_ERROR(RecursivelyCreateDir(pipeline_path));
RETURN_IF_ERROR(WriteStringToFile(pipeline.context(), *context_path));
RETURN_IF_ERROR(WriteStringToFile(pipeline.config(), *config_path));
bf_p4_pipeline_t* pipeline_profile = &p4_program->p4_pipelines[j];
::snprintf(pipeline_profile->p4_pipeline_name, _PI_UPDATE_MAX_NAME_SIZE,
"%s", pipeline.name().c_str());
pipeline_profile->cfg_file = &(*config_path)[0];
pipeline_profile->runtime_context_file = &(*context_path)[0];
path_strings.emplace_back(std::move(config_path));
path_strings.emplace_back(std::move(context_path));
CHECK_RETURN_IF_FALSE(pipeline.scope_size() <= MAX_P4_PIPELINES);
pipeline_profile->num_pipes_in_scope = pipeline.scope_size();
for (int p = 0; p < pipeline.scope_size(); ++p) {
const auto& scope = pipeline.scope(p);
pipeline_profile->pipe_scope[p] = scope;
}
}
}
// This call re-initializes most SDE components.
RETURN_IF_TDI_ERROR(bf_pal_device_add(dev_id, &device_profile));
RETURN_IF_TDI_ERROR(bf_pal_device_warm_init_end(dev_id));
::tdi::DevMgr::getInstance().deviceGet(dev_id, &device);
RETURN_IF_TDI_ERROR(
device->tdiInfoGet(device_config.programs(0).name(), &tdi_info_));
// FIXME: if all we ever do is create and push, this could be one call.
tdi_id_mapper_ = TdiIdMapper::CreateInstance();
RETURN_IF_ERROR(
tdi_id_mapper_->PushForwardingPipelineConfig(device_config, tdi_info_));
return ::util::OkStatus();
}
// Packetio
::util::Status TdiSdeWrapper::TxPacket(int device, const std::string& buffer) {
return ::util::OkStatus();
}
::util::Status TdiSdeWrapper::StartPacketIo(int device) {
return ::util::OkStatus();
}
::util::Status TdiSdeWrapper::StopPacketIo(int device) {
return ::util::OkStatus();
}
// IPsec notification
::util::Status TdiSdeWrapper::InitNotificationTableWithCallback(
int dev_id, std::shared_ptr<TdiSdeInterface::SessionInterface> session,
const std::string& table_name, notification_table_callback_t callback,
void* cookie) const LOCKS_EXCLUDED(data_lock_) {
return MAKE_ERROR(ERR_OPER_NOT_SUPPORTED)
<< "Notification Table not supported";
}
} // namespace tdi
} // namespace hal
} // namespace stratum