-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpfswitch13.cpp
More file actions
424 lines (332 loc) · 14.8 KB
/
pfswitch13.cpp
File metadata and controls
424 lines (332 loc) · 14.8 KB
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/shared_array.hpp>
#include <cstring>
#include <netinet/in.h>
#include <stdexcept>
#include <stdint.h>
#include "openflow-default.hh"
#include "assert.hh"
#include "component.hh"
#include "flow.hh"
#include "fnv_hash.hh"
#include "hash_set.hh"
#include "ofp-msg-event.hh"
#include "vlog.hh"
#include "flowmod.hh"
#include "datapath-join.hh"
#include "datapath-leave.hh"
#include <stdio.h>
#include <cstdio>
#include <cmath>
#include "netinet++/ethernetaddr.hh"
#include "netinet++/ethernet.hh"
#include "../../../oflib/ofl-actions.h"
#include "../../../oflib/ofl-messages.h"
#include <boost/numeric/ublas/vector.hpp>
#include <boost/numeric/ublas/io.hpp>
#include "json-util.hh"
#include "switch13.h"
#include "switchs1.h"
#include "switchs2.h"
#include "switchs3.h"
#include "switchs4.h"
#include "switch13list.h"
#include "groupmod.h"
#include "rregionlist.h"
using namespace vigil;
using namespace vigil::container;
using namespace vigil::json;
using namespace std;
namespace{
Vlog_module log("PFSwitch13");
/// \class PFSwitch13
class PFSwitch13:public Component{
private:
std::string as; ///< Path id is...
double delay; ///< Polling delay.
timeval timeout; ///< Polling delat in timeval.
pfswitch13::Switch13List sw;
json_object *config; ///< The whole cfg file in json.
unsigned active_region; ///< The id of the active region.
pfswitch13::RRegionList regions; ///< The roouting regions and their splitting ratios
std::vector<pfswitch13::Switch13*> src_sw; ///< Switches acting like sources of demands.
boost::numeric::ublas::vector<double> demand; ///< The current demand vector
std::vector<bool> visible; ///< Active source switches.
std::vector<bool> invalid; ///< The invalidated source switches, i.e., switches beeing in wrong routing region.
public:
/// Ctor.
PFSwitch13(const Context* c,const json_object*):Component(c){}
/// Configure.
void configure(const Configuration*);
/// Install handles.
void install();
void swapRRegion(bool=false);
/// New packet without rule.
Disposition handle(const Event&);
/// When router comes up, run this function.
Disposition handle_dp_join(const Event& e);
/// When router switches off.
Disposition handle_dp_leave(const Event& e);
/// When router comes up, run this function.
void handle_timeout();
/// When router comes up, run this function.
Disposition handle_stat(const Event& e);
};
void PFSwitch13::configure(const Configuration* conf){
//Get commandline arguments
std::string input_file;
const hash_map<string, string> argmap=conf->get_arguments_list();
hash_map<string, string>::const_iterator i;
i=argmap.find("cfg");
if(i!=argmap.end()) input_file=i->second;
else exit(-1);
bool delay_set=false;
i=argmap.find("delay");
if(i!=argmap.end()){
delay=atof(i->second.c_str());
delay_set=true;
VLOG_INFO(log,"Query delay set on command line. Delay is %f ms.",delay);
}
json_object *config=load_document(input_file.c_str());
if(!config){
VLOG_ERR(log,"Config file error.");
exit(-1);
}
json_object *ctrl=get_dict_value(config,"controller");
if(!ctrl || ctrl->type==json_object::JSONT_NULL){
VLOG_ERR(log,"Config file error. Cannot understand controller\'s description.");
exit(-1);
}
if(!get_dict_value(ctrl,"as") || get_dict_value(ctrl,"as")->type!=json_object::JSONT_STRING){
VLOG_ERR(log,"Config file error. As wasn\'t specified.");
exit(-1);
}
as=*(char**)get_dict_value(ctrl,"as")->object;
if(!get_dict_value(ctrl,"model") || get_dict_value(ctrl,"model")->type!=json_object::JSONT_STRING){
VLOG_ERR(log,"Config file error. Model wasn\'t specified.");
exit(-1);
}
if(strcmp(*(char**)get_dict_value(ctrl,"model")->object,"pathflow")){
VLOG_ERR(log,"Config file error. Controller speak \'pathflow\' config speaks \'arcflow\'.",(char*)get_dict_value(ctrl,"model")->object);
exit(-1);
}
if(!delay_set){
json_object *d=get_dict_value(ctrl,"delay");
if(d){
if(d->type==json_object::JSONT_FLOAT) delay=*((float*)d->object);
else if(d->type==json_object::JSONT_INTEGER) delay=*((int*)d->object);
VLOG_INFO(log,"Query delay set in controller config file. Delay is %f s.",delay);
}
else{
delay=100;
VLOG_WARN(log,"Query delay not sent. Using %f s.",delay);
}
}
timeout.tv_sec=(unsigned)floor(delay);
timeout.tv_usec=(unsigned)(1000*(delay-floor(delay)));
json_object *connections=get_dict_value(ctrl,"connections");
if(connections && connections->type==json_object::JSONT_ARRAY){
if(!sw.parse((std::list<json_object*>*)connections->object,as)) exit(-1);
}
else{
VLOG_ERR(log,"Cannot find connections in the config file...");
exit(-1);
}
VLOG_INFO(log,"Will install %d switches...",sw.size());
size_t dummy=(size_t)-1; // dummy variable
size_t serial=0;
for(pfswitch13::Switch13List::iterator it=sw.begin();it!=sw.end();++it){
(*it)->init();
if(dynamic_cast<pfswitch13::SwitchS1*>(*it) ||
dynamic_cast<pfswitch13::SwitchS4*>(*it)){
src_sw.push_back(*it);
(*it)->attach((void*)&serial,sizeof(size_t)); // store index in/together with the switch
serial++;
}
else{
(*it)->attach((void*)&dummy,sizeof(size_t)); // store index in/together with the switch
}
}
demand.resize(src_sw.size()); // init the demand vector
invalid.resize(src_sw.size(),true); // each one is invalid
visible.resize(src_sw.size(),false); // there aren't connected switches
VLOG_INFO(log,"Will install %d demands...",src_sw.size());
json_object *regs=get_dict_value(ctrl,"regions");
if(regs && regs->type==json_object::JSONT_ARRAY){
if(!regions.parse((std::list<json_object*>*)regs->object)) exit(-1);
}
else{
VLOG_ERR(log,"No routing function given.");
exit(-1);
}
VLOG_INFO(log,"Nunber of routing regions: %d.",regions.size());
}
void PFSwitch13::install(){
register_handler(Datapath_join_event::static_get_name(),boost::bind(&PFSwitch13::handle_dp_join,this,_1));
register_handler(Datapath_leave_event::static_get_name(),boost::bind(&PFSwitch13::handle_dp_leave,this,_1));
register_handler(Ofp_msg_event::get_name(OFPT_PACKET_IN),boost::bind(&PFSwitch13::handle,this,_1));
register_handler(Ofp_msg_event::get_stats_name(OFPMP_FLOW),boost::bind(&PFSwitch13::handle_stat,this,_1));
post(boost::bind(&PFSwitch13::handle_timeout,this),timeout);
}
void PFSwitch13::swapRRegion(bool anyway){
for(pfswitch13::RRegionList::const_iterator it=regions.begin();it!=regions.end();++it){
if(it->is_active(demand)){
VLOG_INFO(log,"The rid of the currently active regions is %d.",regions.size());
if(anyway || it->rid!=active_region){
for(std::vector<pfswitch13::Switch13*>::iterator it3=src_sw.begin();it3!=src_sw.end();++it3){
if(visible[*(size_t*)((*it3)->getUID())] &&
dynamic_cast<pfswitch13::SwitchS4*>(*it3)){
std::map<std::string,unsigned*> r=it->ratios;
for(std::map<std::string,unsigned*>::iterator it2=r.begin();it2!=r.end();++it2){
if(it2->first==(*it3)->getName()){
(*it3)->switchWeights(it2->second);
invalid[*(size_t*)((*it3)->getUID())]=false;
}
}
}
}
}
else{
for(std::vector<pfswitch13::Switch13*>::iterator it3=src_sw.begin();it3!=src_sw.end();++it3){
if(visible[*(size_t*)((*it3)->getUID())] &&
dynamic_cast<pfswitch13::SwitchS4*>(*it3) &&
invalid[*(size_t*)((*it3)->getUID())]){
std::map<std::string,unsigned*> r=it->ratios;
for(std::map<std::string,unsigned*>::iterator it2=r.begin();it2!=r.end();++it2){
if(it2->first==(*it3)->getName()){
(*it3)->switchWeights(it2->second);
invalid[*(size_t*)((*it3)->getUID())]=false;
}
}
}
}
}
active_region=it->rid;
break;
}
}
}
Disposition PFSwitch13::handle_dp_leave(const Event& e){
const Datapath_leave_event& dpl=assert_cast<const Datapath_leave_event&>(e);
vigil::datapathid dpid=dpl.datapath_id;
for(std::vector<pfswitch13::Switch13*>::iterator it=src_sw.begin();it!=src_sw.end();++it){
if(**it==dpid){
demand(*(size_t*)((*it)->getUID()))=0;
visible[*(size_t*)((*it)->getUID())]=false;
//invalid[*(size_t*)((*it)->getUID())]=true;
}
}
VLOG_DBG(log,"Datapath leave from switch on dpid=0x%"PRIx64".\n",dpl.datapath_id.as_host());
return CONTINUE;
}
Disposition PFSwitch13::handle_dp_join(const Event& e){
const Datapath_join_event& dpj=assert_cast<const Datapath_join_event&>(e);
vigil::datapathid dpid=dpj.dpid;
VLOG_DBG(log,"Datapath join from switch on dpid=0x%"PRIx64".\n",dpj.dpid.as_host());
for(pfswitch13::Switch13List::iterator it=sw.begin();it!=sw.end();++it){
if(**it==dpid){
VLOG_DBG(log,"Installing table(s) to the switch on dpid=0x%"PRIx64".\n",dpj.dpid.as_host());
(*it)->configure();
if(dynamic_cast<pfswitch13::SwitchS1*>(*it) ||
dynamic_cast<pfswitch13::SwitchS4*>(*it)){
demand(*(size_t*)((*it)->getUID()))=0;
visible[*(size_t*)((*it)->getUID())]=true;
invalid[*(size_t*)((*it)->getUID())]=true;
}
VLOG_INFO(log,"Table entries installed successfully.");
}
}
swapRRegion();
return CONTINUE;
}
void PFSwitch13::handle_timeout(){
post(boost::bind(&PFSwitch13::handle_timeout,this),timeout);
for(std::vector<pfswitch13::Switch13*>::iterator it=src_sw.begin();it!=src_sw.end();++it){
if(visible[*(size_t*)((*it)->getUID())])
(*it)->statReq();
}
VLOG_INFO(log,"Stat requests sent successfully.");
}
Disposition PFSwitch13::handle_stat(const Event& e){
const Ofp_msg_event& pi = assert_cast<const Ofp_msg_event&>(e);
datapathid dpid=pi.dpid; // the datapath id
VLOG_INFO(log,"readind flow table stats on dpid=0x%"PRIx64".\n",pi.dpid.as_host());
struct ofl_msg_multipart_reply_flow *in=(struct ofl_msg_multipart_reply_flow*)**pi.msg;
if(in->stats_num!=1){
VLOG_DBG(log,"More than one entry for switch on dpid=0x%"PRIx64".\n",pi.dpid.as_host());
return CONTINUE;
}
Flow t=Flow((ofl_match*)in->stats[0]->match);
VLOG_INFO(log,"oxm-match: %s",t.to_string().c_str());
for(std::vector<pfswitch13::Switch13*>::iterator it=src_sw.begin();it!=src_sw.end();++it){
if(**it==dpid){
if((*it)->same((ofl_match*)in->stats[0]->match)){
uint64_t byte_count=in->stats[0]->byte_count;
demand(*(size_t*)((*it)->getUID()))=byte_count/delay-demand(*(size_t*)((*it)->getUID()));
//std::cerr<<"Demand: "<<demand(*(size_t*)((*it)->getUID()))<<"\n";
}
}
}
swapRRegion();
/*
struct ofl_msg_multipart_reply_header{
struct ofl_msg_header header; // OFPT_MULTIPART_REPLY
enum ofp_multipart_types type; // One of the OFPMP_* constants.
uint16_t flags;
};
struct ofl_msg_multipart_reply_flow{
struct ofl_msg_multipart_reply_header header; // OFPMP_FLOW
size_t stats_num;
struct ofl_flow_stats **stats;
};
struct ofl_flow_stats{
uint8_t table_id; // ID of table flow came from.
uint32_t duration_sec; // Time flow has been alive in secs.
uint32_t duration_nsec; // Time flow has been alive in nsecs beyond duration_sec.
uint16_t priority; // Priority of the entry. Only meaningful when this is not an exact-match entry.
uint16_t idle_timeout; // Number of seconds idle before expiration.
uint16_t hard_timeout; // Number of seconds before expiration.
uint64_t cookie; // Opaque controller-issued identifier.
uint64_t packet_count; // Number of packets in flow.
uint64_t byte_count; // Number of bytes in flow.
struct ofl_match_header *match; // Description of fields.
size_t instructions_num;
struct ofl_instruction_header **instructions; // Instruction set.
};
*/
return CONTINUE;
}
Disposition PFSwitch13::handle(const Event& e){
const Ofp_msg_event& pi = assert_cast<const Ofp_msg_event&>(e);
struct ofl_msg_packet_in *in = (struct ofl_msg_packet_in *)**pi.msg;
Flow *flow = new Flow((struct ofl_match*) in->match);
/* drop all LLDP packets */
uint16_t dl_type;
flow->get_Field<uint16_t>("eth_type",&dl_type);
if (dl_type == ethernet::LLDP){
return CONTINUE;
}
uint32_t in_port;
flow->get_Field<uint32_t>("in_port",&in_port);
/* Figure out the destination. */
int out_port = -1; /* Flood by default. */
uint8_t eth_dst[6];
/* Send out packet if necessary. */
if (in->buffer_id == UINT32_MAX) {
if (in->total_len != in->data_length) {
/* Control path didn't buffer the packet and didn't send us
* the whole thing--what gives? */
VLOG_DBG(log, "total_len=%"PRIu16" data_len=%zu\n",
in->total_len, in->data_length);
return CONTINUE;
}
send_openflow_pkt(pi.dpid, Nonowning_buffer(in->data, in->data_length), in_port, out_port == -1 ? OFPP_FLOOD : out_port, true/*block*/);
}
else {
send_openflow_pkt(pi.dpid, in->buffer_id, in_port, out_port == -1 ? OFPP_FLOOD : out_port, true/*block*/);
}
return CONTINUE;
}
REGISTER_COMPONENT(container::Simple_component_factory<PFSwitch13>, PFSwitch13);
} // unnamed namespace