Skip to content

Commit c3be442

Browse files
committed
add primitives for v1model
1 parent 648aabe commit c3be442

30 files changed

Lines changed: 1601 additions & 503 deletions

CMakeLists.txt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ list(APPEND third_party_libs -L/usr/local/lib)
4646
# Core module construction
4747
build_lib(
4848
LIBNAME p4sim
49-
SOURCE_FILES # equivalent to module.source
50-
model/p4-queue.cc
49+
SOURCE_FILES # equivalent to module.source utils/format-utils.cc
50+
utils/format-utils.cc
51+
utils/switch-api.cc
52+
utils/p4-queue.cc
5153
model/p4-bridge-channel.cc
5254
model/p4-p2p-channel.cc
5355
model/custom-header.cc
@@ -59,13 +61,15 @@ build_lib(
5961
model/p4-nic-pna.cc
6062
model/p4-switch-net-device.cc
6163
model/custom-p2p-net-device.cc
62-
model/format-utils.cc
63-
model/switch-api.cc
6464
helper/p4-helper.cc
6565
helper/p4-topology-reader-helper.cc
6666
helper/p4-p2p-helper.cc
6767
HEADER_FILES # equivalent to headers.source
68-
model/p4-queue.h
68+
utils/p4-queue.h
69+
utils/format-utils.h
70+
utils/switch-api.h
71+
utils/register-access-v1model.h
72+
utils/primitives-v1model.h
6973
model/p4-bridge-channel.h
7074
model/p4-p2p-channel.h
7175
model/custom-header.h
@@ -77,9 +81,6 @@ build_lib(
7781
model/p4-nic-pna.h
7882
model/p4-switch-net-device.h
7983
model/custom-p2p-net-device.h
80-
model/format-utils.h
81-
model/switch-api.h
82-
model/register_access.h
8384
helper/p4-helper.h
8485
helper/p4-topology-reader-helper.h
8586
helper/p4-p2p-helper.h

deprecated/p4-core-pipeline.cc

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* Copyright (c)
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License version 2 as
6+
* published by the Free Software Foundation;
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program; if not, write to the Free Software
15+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16+
*
17+
* Author: Jiasong Bai
18+
* Modified: Mingyu Ma<[email protected]>
19+
*/
20+
21+
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_OFF
22+
23+
#ifdef Mutex
24+
#undef Mutex
25+
#endif
26+
27+
#ifdef registry_t
28+
#undef registry_t
29+
#endif
30+
31+
#include <bm/spdlog/spdlog.h>
32+
#undef LOG_INFO
33+
#undef LOG_ERROR
34+
#undef LOG_DEBUG
35+
36+
#include "ns3/ethernet-header.h"
37+
#include "ns3/log.h"
38+
#include "ns3/p4-core-pipeline.h"
39+
#include "ns3/register_access.h"
40+
#include "ns3/simulator.h"
41+
#include "ns3/socket.h"
42+
43+
#include <bm/bm_runtime/bm_runtime.h>
44+
#include <bm/bm_sim/options_parse.h>
45+
#include <bm/bm_sim/parser.h>
46+
#include <bm/bm_sim/phv.h>
47+
48+
NS_LOG_COMPONENT_DEFINE("P4CorePipeline");
49+
50+
namespace ns3
51+
{
52+
53+
namespace
54+
{
55+
56+
struct hash_ex_v1model_pipeline
57+
{
58+
uint32_t operator()(const char* buf, size_t s) const
59+
{
60+
const uint32_t p = 16777619;
61+
uint32_t hash = 2166136261;
62+
63+
for (size_t i = 0; i < s; i++)
64+
hash = (hash ^ buf[i]) * p;
65+
66+
hash += hash << 13;
67+
hash ^= hash >> 7;
68+
hash += hash << 3;
69+
hash ^= hash >> 17;
70+
hash += hash << 5;
71+
return static_cast<uint32_t>(hash);
72+
}
73+
};
74+
75+
struct bmv2_hash_v1model_pipeline
76+
{
77+
uint64_t operator()(const char* buf, size_t s) const
78+
{
79+
return bm::hash::xxh64(buf, s);
80+
}
81+
};
82+
83+
} // namespace
84+
85+
// if REGISTER_HASH calls placed in the anonymous namespace, some compiler can
86+
// give an unused variable warning
87+
REGISTER_HASH(hash_ex_v1model_pipeline);
88+
REGISTER_HASH(bmv2_hash_v1model_pipeline);
89+
90+
P4CorePipeline::P4CorePipeline(P4SwitchNetDevice* netDevice,
91+
bool enableSwap,
92+
bool enableTracing,
93+
uint32_t drop_port)
94+
: bm::Switch(enableSwap),
95+
m_enableTracing(enableTracing),
96+
m_enableSwap(enableSwap),
97+
m_dropPort(drop_port)
98+
{
99+
m_packetId = 0;
100+
101+
add_required_field("standard_metadata", "ingress_port");
102+
add_required_field("standard_metadata", "packet_length");
103+
add_required_field("standard_metadata", "instance_type");
104+
add_required_field("standard_metadata", "egress_spec");
105+
add_required_field("standard_metadata", "egress_port");
106+
107+
force_arith_header("standard_metadata");
108+
// force_arith_header("queueing_metadata");
109+
force_arith_header("intrinsic_metadata");
110+
111+
static int switch_id = 1;
112+
m_p4SwitchId = switch_id++;
113+
NS_LOG_INFO("Init P4 Switch with ID: " << m_p4SwitchId);
114+
115+
m_switchNetDevice = netDevice;
116+
}
117+
118+
P4CorePipeline::~P4CorePipeline()
119+
{
120+
NS_LOG_FUNCTION(this);
121+
NS_LOG_INFO("Destroying P4CorePipeline.");
122+
}
123+
124+
void
125+
P4CorePipeline::InitSwitchWithP4(std::string jsonPath, std::string flowTablePath)
126+
{
127+
// Log function entry
128+
NS_LOG_FUNCTION(this);
129+
NS_LOG_INFO("Initializing P4CorePipeline.");
130+
131+
// Initialize status flag and Thrift port
132+
int status = 0;
133+
static int p4_switch_ctrl_plane_thrift_port = 9090;
134+
m_thriftPort = p4_switch_ctrl_plane_thrift_port;
135+
136+
// Configure OptionsParser
137+
bm::OptionsParser opt_parser;
138+
opt_parser.config_file_path = jsonPath;
139+
opt_parser.debugger_addr = "ipc:///tmp/bmv2-v1model-" +
140+
std::to_string(p4_switch_ctrl_plane_thrift_port) + "-debug.ipc";
141+
opt_parser.notifications_addr = "ipc:///tmp/bmv2-v1model-" +
142+
std::to_string(p4_switch_ctrl_plane_thrift_port) +
143+
"-notifications.ipc";
144+
opt_parser.file_logger =
145+
"/tmp/bmv2-v1model-" + std::to_string(p4_switch_ctrl_plane_thrift_port) + "-pipeline.log";
146+
opt_parser.thrift_port = p4_switch_ctrl_plane_thrift_port++;
147+
opt_parser.console_logging = false;
148+
149+
// Initialize the switch
150+
status = init_from_options_parser(opt_parser);
151+
if (status != 0)
152+
{
153+
NS_LOG_ERROR("Failed to initialize P4CorePipeline.");
154+
return; // Avoid exiting simulation
155+
}
156+
157+
// Start the runtime server
158+
int port = get_runtime_port();
159+
bm_runtime::start_server(this, port);
160+
161+
// Populate flow table using CLI command
162+
std::string cmd = "simple_switch_CLI --thrift-port " + std::to_string(port) + " < " +
163+
flowTablePath + " > /dev/null 2>&1";
164+
165+
int result = std::system(cmd.c_str());
166+
167+
// Wait for the server to be ready
168+
sleep(1);
169+
if (result != 0)
170+
{
171+
NS_LOG_ERROR("Error executing flow table population command: " << cmd);
172+
}
173+
174+
NS_LOG_INFO("P4CorePipeline initialization completed successfully.");
175+
}
176+
177+
int
178+
P4CorePipeline::InitFromCommandLineOptions(int argc, char* argv[])
179+
{
180+
bm::OptionsParser parser;
181+
parser.parse(argc, argv, m_argParser);
182+
183+
// create a dummy transport
184+
std::shared_ptr<bm::TransportIface> transport =
185+
std::shared_ptr<bm::TransportIface>(bm::TransportIface::make_dummy());
186+
187+
int status = 0;
188+
if (parser.no_p4)
189+
// with out p4-json, acctually the switch will wait for the
190+
// configuration(p4-json) before work
191+
status = init_objects_empty(parser.device_id, transport);
192+
else
193+
// load p4 configuration files xxxx.json to switch
194+
status = init_objects(parser.config_file_path, parser.device_id, transport);
195+
return status;
196+
}
197+
198+
void
199+
P4CorePipeline::RunCli(const std::string& commandsFile)
200+
{
201+
NS_LOG_FUNCTION(this << " Switch ID: " << m_p4SwitchId << " Running CLI commands from "
202+
<< commandsFile);
203+
204+
int port = get_runtime_port();
205+
bm_runtime::start_server(this, port);
206+
// start_and_return ();
207+
NS_LOG_DEBUG("Switch ID: " << m_p4SwitchId << " Waiting for the runtime server to start");
208+
std::this_thread::sleep_for(std::chrono::seconds(3));
209+
210+
// Run the CLI commands to populate table entries
211+
std::string cmd = "run_bmv2_CLI --thrift_port " + std::to_string(port) + " " + commandsFile;
212+
int res = std::system(cmd.c_str());
213+
(void)res;
214+
}
215+
216+
int
217+
P4CorePipeline::receive_(uint32_t port_num, const char* buffer, int len)
218+
{
219+
NS_LOG_FUNCTION(this << " Switch ID: " << m_p4SwitchId << " Port: " << port_num
220+
<< " Len: " << len);
221+
return 0;
222+
}
223+
224+
void
225+
P4CorePipeline::start_and_return_()
226+
{
227+
NS_LOG_FUNCTION("Switch ID: " << m_p4SwitchId << " start");
228+
}
229+
230+
void
231+
P4CorePipeline::swap_notify_()
232+
{
233+
NS_LOG_FUNCTION("p4_switch has been notified of a config swap");
234+
}
235+
236+
void
237+
P4CorePipeline::reset_target_state_()
238+
{
239+
NS_LOG_DEBUG("Resetting target-specific state, not supported.");
240+
}
241+
242+
int
243+
P4CorePipeline::P4ProcessingPipeline(Ptr<Packet> packetIn,
244+
int inPort,
245+
uint16_t protocol,
246+
const Address& destination)
247+
{
248+
NS_LOG_FUNCTION(this);
249+
250+
// === Convert ns-3 packet to bm packet
251+
std::unique_ptr<bm::Packet> bm_packet = ConvertToBmPacket(packetIn, inPort);
252+
253+
bm::PHV* phv = bm_packet->get_phv();
254+
uint32_t len = bm_packet.get()->get_data_size();
255+
bm_packet.get()->set_ingress_port(inPort);
256+
257+
phv->reset_metadata();
258+
phv->get_field("standard_metadata.ingress_port").set(inPort);
259+
bm_packet->set_register(RegisterAccess::PACKET_LENGTH_REG_IDX, len);
260+
phv->get_field("standard_metadata.packet_length").set(len);
261+
bm::Field& f_instance_type = phv->get_field("standard_metadata.instance_type");
262+
f_instance_type.set(PKT_INSTANCE_TYPE_NORMAL);
263+
264+
// === Parser and MAU processing
265+
bm::Parser* parser = this->get_parser("parser");
266+
bm::Pipeline* ingress_mau = this->get_pipeline("ingress");
267+
parser->parse(bm_packet.get());
268+
ingress_mau->apply(bm_packet.get());
269+
270+
bm_packet->reset_exit();
271+
bm::Field& f_egress_spec = phv->get_field("standard_metadata.egress_spec");
272+
uint32_t egress_spec = f_egress_spec.get_uint();
273+
274+
// LEARNING
275+
int learn_id = RegisterAccess::get_lf_field_list(bm_packet.get());
276+
if (learn_id > 0)
277+
{
278+
get_learn_engine()->learn(learn_id, *bm_packet.get());
279+
}
280+
281+
// === Egress
282+
bm::Pipeline* egress_mau = this->get_pipeline("egress");
283+
bm::Deparser* deparser = this->get_deparser("deparser");
284+
phv->get_field("standard_metadata.egress_port").set(egress_spec);
285+
f_egress_spec = phv->get_field("standard_metadata.egress_spec");
286+
f_egress_spec.set(0);
287+
288+
phv->get_field("standard_metadata.packet_length")
289+
.set(bm_packet->get_register(RegisterAccess::PACKET_LENGTH_REG_IDX));
290+
291+
egress_mau->apply(bm_packet.get());
292+
293+
// === Deparser
294+
deparser->deparse(bm_packet.get());
295+
296+
// === Send the packet to the destination
297+
Ptr<Packet> ns_packet = ConvertToNs3Packet(std::move(bm_packet));
298+
m_switchNetDevice->SendNs3Packet(ns_packet, egress_spec, protocol, destination);
299+
return 0;
300+
}
301+
302+
Ptr<Packet>
303+
P4CorePipeline::ConvertToNs3Packet(std::unique_ptr<bm::Packet>&& bm_packet)
304+
{
305+
// Create a new ns3::Packet using the data buffer
306+
char* bm_buf = bm_packet.get()->data();
307+
size_t len = bm_packet.get()->get_data_size();
308+
Ptr<Packet> ns_packet = Create<Packet>((uint8_t*)(bm_buf), len);
309+
310+
return ns_packet;
311+
}
312+
313+
std::unique_ptr<bm::Packet>
314+
P4CorePipeline::ConvertToBmPacket(Ptr<Packet> nsPacket, int inPort)
315+
{
316+
int len = nsPacket->GetSize();
317+
uint8_t* pkt_buffer = new uint8_t[len];
318+
nsPacket->CopyData(pkt_buffer, len);
319+
bm::PacketBuffer buffer(len + 512, (char*)pkt_buffer, len);
320+
std::unique_ptr<bm::Packet> bm_packet(
321+
new_packet_ptr(inPort, m_packetId++, len, std::move(buffer)));
322+
delete[] pkt_buffer;
323+
324+
return bm_packet;
325+
}
326+
327+
} // namespace ns3

0 commit comments

Comments
 (0)