-
Notifications
You must be signed in to change notification settings - Fork 334
/
Copy pathsimple_switch.h
203 lines (159 loc) · 5.84 KB
/
simple_switch.h
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
/* Copyright 2013-present Barefoot Networks, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Antonin Bas ([email protected])
*
*/
#ifndef SIMPLE_SWITCH_SIMPLE_SWITCH_H_
#define SIMPLE_SWITCH_SIMPLE_SWITCH_H_
#include <bm/bm_sim/queue.h>
#include <bm/bm_sim/queueing.h>
#include <bm/bm_sim/packet.h>
#include <bm/bm_sim/switch.h>
#include <bm/bm_sim/event_logger.h>
#include <bm/bm_sim/simple_pre_lag.h>
#include <memory>
#include <chrono>
#include <thread>
#include <vector>
#include <functional>
// TODO(antonin)
// experimental support for priority queueing
// to enable it, uncomment this flag
// you can also choose the field from which the priority value will be read, as
// well as the number of priority queues per port
// PRIORITY 0 IS THE LOWEST PRIORITY
#define SSWITCH_PRIORITY_QUEUEING_SRC "intrinsic_metadata.priority"
using ts_res = std::chrono::microseconds;
using std::chrono::duration_cast;
using ticks = std::chrono::nanoseconds;
using bm::Switch;
using bm::Queue;
using bm::Packet;
using bm::PHV;
using bm::Parser;
using bm::Deparser;
using bm::Pipeline;
using bm::McSimplePreLAG;
using bm::Field;
using bm::FieldList;
using bm::packet_id_t;
using bm::p4object_id_t;
class SimpleSwitch : public Switch {
public:
using mirror_id_t = int;
using TransmitFn = std::function<void(port_t, packet_id_t,
const char *, int)>;
struct MirroringSessionConfig {
port_t egress_port;
bool egress_port_valid;
unsigned int mgid;
bool mgid_valid;
};
static constexpr port_t default_drop_port = 511;
static constexpr size_t default_nb_queues_per_port = 1;
private:
using clock = std::chrono::high_resolution_clock;
public:
// by default, swapping is off
explicit SimpleSwitch(bool enable_swap = false,
port_t drop_port = default_drop_port,
size_t nb_queues_per_port = default_nb_queues_per_port);
~SimpleSwitch();
int receive_(port_t port_num, const char *buffer, int len) override;
void start_and_return_() override;
void reset_target_state_() override;
void swap_notify_() override;
bool mirroring_add_session(mirror_id_t mirror_id,
const MirroringSessionConfig &config);
bool mirroring_delete_session(mirror_id_t mirror_id);
bool mirroring_get_session(mirror_id_t mirror_id,
MirroringSessionConfig *config) const;
int set_egress_priority_queue_depth(size_t port, size_t priority,
const size_t depth_pkts);
int set_egress_queue_depth(size_t port, const size_t depth_pkts);
int set_all_egress_queue_depths(const size_t depth_pkts);
int set_egress_priority_queue_rate(size_t port, size_t priority,
const uint64_t rate_pps);
int set_egress_queue_rate(size_t port, const uint64_t rate_pps);
int set_all_egress_queue_rates(const uint64_t rate_pps);
// returns the number of microseconds elapsed since the switch started
uint64_t get_time_elapsed_us() const;
// returns the number of microseconds elasped since the clock's epoch
uint64_t get_time_since_epoch_us() const;
// returns the packet id of most recently received packet. Not thread-safe.
static packet_id_t get_packet_id() {
return packet_id - 1;
}
void set_transmit_fn(TransmitFn fn);
port_t get_drop_port() const {
return drop_port;
}
SimpleSwitch(const SimpleSwitch &) = delete;
SimpleSwitch &operator =(const SimpleSwitch &) = delete;
SimpleSwitch(SimpleSwitch &&) = delete;
SimpleSwitch &&operator =(SimpleSwitch &&) = delete;
private:
static constexpr size_t nb_egress_threads = 4u;
static packet_id_t packet_id;
class MirroringSessions;
class InputBuffer;
enum PktInstanceType {
PKT_INSTANCE_TYPE_NORMAL,
PKT_INSTANCE_TYPE_INGRESS_CLONE,
PKT_INSTANCE_TYPE_EGRESS_CLONE,
PKT_INSTANCE_TYPE_COALESCED,
PKT_INSTANCE_TYPE_RECIRC,
PKT_INSTANCE_TYPE_REPLICATION,
PKT_INSTANCE_TYPE_RESUBMIT,
};
struct EgressThreadMapper {
explicit EgressThreadMapper(size_t nb_threads)
: nb_threads(nb_threads) { }
size_t operator()(size_t egress_port) const {
return egress_port % nb_threads;
}
size_t nb_threads;
};
private:
void ingress_thread();
void egress_thread(size_t worker_id);
void transmit_thread();
ts_res get_ts() const;
// TODO(antonin): switch to pass by value?
void enqueue(port_t egress_port, std::unique_ptr<Packet> &&packet);
void copy_field_list_and_set_type(
const std::unique_ptr<Packet> &packet,
const std::unique_ptr<Packet> &packet_copy,
PktInstanceType copy_type, p4object_id_t field_list_id);
void check_queueing_metadata();
void multicast(Packet *packet, unsigned int mgid);
private:
port_t drop_port;
std::vector<std::thread> threads_;
std::unique_ptr<InputBuffer> input_buffer;
// for these queues, the write operation is non-blocking and we drop the
// packet if the queue is full
size_t nb_queues_per_port;
bm::QueueingLogicPriRL<std::unique_ptr<Packet>, EgressThreadMapper>
egress_buffers;
Queue<std::unique_ptr<Packet> > output_buffer;
TransmitFn my_transmit_fn;
std::shared_ptr<McSimplePreLAG> pre;
clock::time_point start;
bool with_queueing_metadata{false};
std::unique_ptr<MirroringSessions> mirroring_sessions;
};
#endif // SIMPLE_SWITCH_SIMPLE_SWITCH_H_