forked from OFLOPS-Turbo/oflops-turbo
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontrol.cpp
More file actions
187 lines (167 loc) · 6.04 KB
/
control.cpp
File metadata and controls
187 lines (167 loc) · 6.04 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
#include <fluid/OFServer.hh>
#include <fluid/OFServerSettings.hh>
#include <fluid/TLS.hh>
extern "C" {
#include "control.h"
#include "utils.h"
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "event2/event.h"
#include <poll.h>
#include <netinet/tcp.h>
}
#include <condition_variable>
#include <iostream>
#include <netinet/in.h>
#include <iostream>
std::condition_variable wait_connected;
std::mutex wait_connected_m;
/* A conversion layer between C and C++ allowing us to
* use the libfluid base to handle our connection */
class BasicTestServer : public fluid_base::OFServer{
public:
oflops_context *ctx;
static bool onlydelete;
using fluid_base::OFServer::OFServer;
using fluid_base::OFServer::start;
using fluid_base::OFServer::stop;
fluid_base::OFConnection::Event state;
virtual void message_callback(fluid_base::OFConnection* ofconn, uint8_t type, void* data, size_t len) {
if (ctx->curr_test == NULL)
return;
ctx->curr_test->of_message(ctx, ofconn->get_version(), type, data, len);
}
virtual void connection_callback(fluid_base::OFConnection* ofconn, fluid_base::OFConnection::Event type) {
using namespace fluid_base;
switch(type) {
case OFConnection::EVENT_STARTED:
std::cout<<"Connection id="<<ofconn->get_id()<<" started"<<std::endl;
break;
case OFConnection::EVENT_ESTABLISHED:
std::cout<<"Connection id="<<ofconn->get_id()<<" established"<<std::endl;
break;
case OFConnection::EVENT_FAILED_NEGOTIATION:
std::cout<<"Connection id="<<ofconn->get_id()<<" failed version negotiation"<<std::endl;
break;
case OFConnection::EVENT_CLOSED:
std::cout<<"Connection id="<<ofconn->get_id()<<" closed by the user"<<std::endl;
break;
case OFConnection::EVENT_DEAD:
std::cout<<"Connection id="<<ofconn->get_id()<<" closed due to inactivity"<<std::endl;
break;
}
{
std::unique_lock<std::mutex> locker(wait_connected_m);
state = type;
}
wait_connected.notify_all();
}
bool has_backlog() {
#ifdef HAS_GET_FD
fluid_base::OFConnection *conn = get_ofconnection(0);
struct pollfd fds = {0};
fds.fd = conn->get_fd();
fds.events = POLLOUT;
poll(&fds, 1, 0);
return fds.revents&POLLOUT ? false : true;
#else
return false;
#endif
}
};
static int check_of_version_allowed(oflops_context *ctx, uint8_t v) {
if (ctx->nb_of_versions == 0)
return 1;
for (size_t i = 0; i < ctx->nb_of_versions; i++) {
if (v == ctx->of_versions[i])
return 1;
}
return 0;
}
extern "C" int setup_control_channel(oflops_context *ctx) {
using namespace fluid_base;
int fd;
struct sockaddr_in *sinptr;
struct ifreq ifr;
OFServerSettings options;
int one = 1;
fd = socket(AF_INET, SOCK_DGRAM, 0);
/*
* Get the name of the interface on which the socket was opened.
*/
strncpy(ifr.ifr_name,ctx->channels[OFLOPS_CONTROL].dev,IFNAMSIZ);
if( ioctl( fd, SIOCGIFADDR, &ifr) == -1 )
perror_and_exit("ioctl() SIOCGIFADDR to dev",1);
close(fd);
sinptr = (struct sockaddr_in *) & ifr.ifr_addr;
char *address = inet_ntoa(sinptr->sin_addr);
bool use_tls = false;
if (ctx->tls_cert && ctx->tls_privkey && ctx->tls_trustedcert) {
std::cerr<<"using tls!!\n";
fluid_base::libfluid_tls_init(ctx->tls_cert, ctx->tls_privkey, ctx->tls_trustedcert);
use_tls = true;
}
if (ctx->curr_test->get_openflow_versions()) {
const uint8_t *ofvs = ctx->curr_test->get_openflow_versions();
std::cout<<"Adding openflow versions ";
for (int i = 0; ofvs[i]; i++) {
if (check_of_version_allowed(ctx, ofvs[i])) {
std::cout<<(int) ofvs[i]<<"," ;
options.supported_version(ofvs[i]);
}
}
std::cout<<" to openflow handshake"<<std::endl;
}
options.echo_interval(10000);
options.use_hello_elements(true);
auto ser = new BasicTestServer(address, ctx->listen_port, 1, use_tls, options);
ctx->fluid_control = static_cast<void *>(ser);
ser->ctx = ctx;
ser->state = OFConnection::EVENT_DEAD;
ser->start();
std::cout<<"Waiting for a switch to connect...\n";
// Wait for connection?
std::unique_lock<std::mutex> locker(wait_connected_m);
while ((ser->get_ofconnection(0) == NULL
|| ser->get_ofconnection(0)->get_state() == OFConnection::STATE_HANDSHAKE)
&& ser->state != OFConnection::EVENT_FAILED_NEGOTIATION) {
wait_connected.wait(locker);
}
if (ser->get_ofconnection(0)->get_state() == OFConnection::STATE_FAILED ||
ser->state == OFConnection::EVENT_FAILED_NEGOTIATION) {
std::cerr<<"Connection failed, likely failed negotiation."<<std::endl;
abort();
}
#ifdef HAS_GET_FD
fd = ser->get_ofconnection(0)->get_fd();
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0) {
std::cerr<<"Failed to disable nagle!!"<<std::endl;
}
#else
#warning "Will not support TCP_NODELAY"
#endif
std::cout<<"Ready to generate!!"<<std::endl;
ctx->of_version = ser->get_ofconnection(0) ? ser->get_ofconnection(0)->get_version() : 0;
return 0;
}
extern "C" void teardown_control_channel(oflops_context *ctx) {
BasicTestServer *test = static_cast<BasicTestServer *>(ctx->fluid_control);
test->stop();
delete test;
ctx->fluid_control = NULL;
}
extern "C" int write_oflops_control(oflops_context *ctx, void* data, size_t len) {
BasicTestServer *test = static_cast<BasicTestServer *>(ctx->fluid_control);
if (len == 0) {
len = ntohs(((struct ofp_header *) data)->length);
}
test->get_ofconnection(0)->send(data, len);
return 0;
}
extern "C" int has_control_backlog(oflops_context *ctx) {
BasicTestServer *test = static_cast<BasicTestServer *>(ctx->fluid_control);
return test->has_backlog();
}