Skip to content

Commit

Permalink
Create/delete mirror and associated output port in same call
Browse files Browse the repository at this point in the history
Mock sendMessage behavior a little better to increase UT coverage
Remove some dead code related to removed sync OVSDB calls

Signed-off-by: Tom Flynn <tom.flynn@gmail.com>
  • Loading branch information
tomflynn committed Jun 12, 2020
1 parent 3b4e2ad commit a153321
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 151 deletions.
219 changes: 110 additions & 109 deletions agent-ovs/ovs/SpanRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,7 @@ namespace opflexagent {

void SpanRenderer::sessionDeleted(const string& sessionName) {
LOG(INFO) << "deleting session " << sessionName;
deleteMirror(sessionName);
LOG(INFO) << "deleting erspan port " << (ERSPAN_PORT_PREFIX + sessionName);
deleteErspanPort(ERSPAN_PORT_PREFIX + sessionName);
deleteMirrorAndOutputPort(sessionName);
}

void SpanRenderer::handleSpanUpdate(const opflex::modb::URI& spanURI) {
Expand Down Expand Up @@ -218,121 +216,116 @@ namespace opflexagent {
}
}
LOG(DEBUG) << "Updating mirror config with srcport count = " << srcPort.size() << " and dstport count = " << dstPort.size();
deleteMirrorAndOutputPort(seSt->getName());

deleteErspanPort(ERSPAN_PORT_PREFIX + seSt->getName());
addErspanPort(ERSPAN_PORT_PREFIX + seSt->getName(), seSt->getDestination().to_string(), seSt->getVersion());
LOG(DEBUG) << "creating mirror";
deleteMirror(seSt->getName());
createMirror(seSt->getName(), srcPort, dstPort);
createMirrorAndOutputPort(seSt->getName(), srcPort, dstPort, seSt->getDestination().to_string(), seSt->getVersion());
}

void SpanRenderer::deleteMirror(const string& sessionName) {
LOG(DEBUG) << "deleting mirror " << sessionName;
void SpanRenderer::deleteMirrorAndOutputPort(const string& sessionName) {
const string erspanOutputPortName = ERSPAN_PORT_PREFIX + sessionName;
LOG(DEBUG) << "deleting mirror " << sessionName << " and erspan port " << erspanOutputPortName;
string sessionUuid;
conn->getOvsdbState().getUuidForName(OvsdbTable::MIRROR, sessionName, sessionUuid);
if (sessionUuid.empty()) {
bool foundSession = !sessionUuid.empty();
if (!foundSession) {
LOG(INFO) << "Unable to find session " << sessionName << " to delete";
}
string erspanPortUuid;
conn->getOvsdbState().getUuidForName(OvsdbTable::PORT, erspanOutputPortName, erspanPortUuid);
bool foundPort = !erspanPortUuid.empty();
if (!foundPort) {
LOG(DEBUG) << "Port is not present in OVSDB: " << erspanOutputPortName;
}
if (!foundPort && !foundSession) {
// nothing to do
LOG(DEBUG) << "Unable to find port or session for name " << sessionName;
return;
}

OvsdbTransactMessage msg(OvsdbOperation::MUTATE, OvsdbTable::BRIDGE);
set<tuple<string, OvsdbFunction, string>> condSet;
condSet.emplace("name", OvsdbFunction::EQ, switchName);
msg.conditions = condSet;

vector<OvsdbValue> values;
values.emplace_back("uuid", sessionUuid);
OvsdbValues tdSet = OvsdbValues(values);
msg.mutateRowData.emplace("mirrors", std::make_pair(OvsdbOperation::DELETE, tdSet));

list<OvsdbTransactMessage> requests = {msg};
sendAsyncTransactRequests(requests);
}

void SpanRenderer::addErspanPort(const string& portName, const string& remoteIp, const uint8_t version) {
LOG(DEBUG) << "adding erspan port " << portName << " IP " << remoteIp << " and version " << std::to_string(version);

OvsdbTransactMessage msg1(OvsdbOperation::INSERT, OvsdbTable::PORT);
vector<OvsdbValue> values;
values.emplace_back(portName);
OvsdbValues tdSet(values);
msg1.rowData.emplace("name", tdSet);

// uuid-name
const string uuid_name = "port1";
msg1.externalKey = make_pair("uuid-name", uuid_name);

// interfaces
values.clear();
const string named_uuid = "interface1";
values.emplace_back("named-uuid", named_uuid);
OvsdbValues tdSet2(values);
msg1.rowData.emplace("interfaces", tdSet2);

// uuid-name
OvsdbTransactMessage msg2(OvsdbOperation::INSERT, OvsdbTable::INTERFACE);
msg2.externalKey = make_pair("uuid-name", named_uuid);

// row entries
// name
values.clear();
values.emplace_back(portName);
OvsdbValues tdSet3(values);
msg2.rowData.emplace("name", tdSet3);

values.clear();
const string typeString("erspan");
OvsdbValue typeData(typeString);
values.push_back(typeData);
OvsdbValues tdSet4(values);
msg2.rowData.emplace("type", tdSet4);

values.clear();
values.emplace_back("erspan_ver", std::to_string(version));
values.emplace_back("remote_ip", remoteIp);
OvsdbValues tdSet5("map", values);
msg2.rowData.emplace("options", tdSet5);

OvsdbTransactMessage msg3(OvsdbOperation::MUTATE, OvsdbTable::BRIDGE);
values.clear();
values.emplace_back("named-uuid", uuid_name);
OvsdbValues tdSet6(values);
msg3.mutateRowData.emplace("ports", std::make_pair(OvsdbOperation::INSERT, tdSet6));
set<tuple<string, OvsdbFunction, string>> condSet;
condSet.emplace("name", OvsdbFunction::EQ, switchName);
msg3.conditions = condSet;

const list<OvsdbTransactMessage> requests = {msg1, msg2, msg3};
sendAsyncTransactRequests(requests);
}

void SpanRenderer::deleteErspanPort(const string& name) {
LOG(DEBUG) << "deleting erspan port " << name;
string erspanUuid;
conn->getOvsdbState().getUuidForName(OvsdbTable::PORT, name, erspanUuid);
if (erspanUuid.empty()) {
LOG(DEBUG) << "Port is not present in OVSDB: " << name;
return;
if (foundSession) {
vector<OvsdbValue> values;
values.emplace_back("uuid", sessionUuid);
OvsdbValues tdSet = OvsdbValues(values);
msg.mutateRowData.emplace("mirrors", std::make_pair(OvsdbOperation::DELETE, tdSet));
}
if (foundPort) {
vector<OvsdbValue> values;
values.emplace_back("uuid", erspanPortUuid);
OvsdbValues tdSet = OvsdbValues(values);
msg.mutateRowData.emplace("ports", std::make_pair(OvsdbOperation::DELETE, tdSet));
}
LOG(DEBUG) << name << " port uuid: " << erspanUuid;
OvsdbTransactMessage msg1(OvsdbOperation::MUTATE, OvsdbTable::BRIDGE);
set<tuple<string, OvsdbFunction, string>> condSet;
condSet.emplace("name", OvsdbFunction::EQ, switchName);
msg1.conditions = condSet;

vector<OvsdbValue> values;
values.emplace_back("uuid", erspanUuid);
OvsdbValues tdSet = OvsdbValues(values);
msg1.mutateRowData.emplace("ports", std::make_pair(OvsdbOperation::DELETE, tdSet));
LOG(DEBUG) << "deleting " << erspanUuid;
const list<OvsdbTransactMessage> requests = {msg1};
const list<OvsdbTransactMessage> requests = {msg};
sendAsyncTransactRequests(requests);
}

void SpanRenderer::createMirror(const string& sess, const set<string>& srcPorts, const set<string>& dstPorts) {
void SpanRenderer::createMirrorAndOutputPort(const string& sess, const set<string>& srcPorts,
const set<string>& dstPorts, const string& remoteIp, const uint8_t version) {
string brUuid;
conn->getOvsdbState().getBridgeUuid(switchName, brUuid);
LOG(DEBUG) << "bridge uuid " << brUuid;

list<OvsdbTransactMessage> requests;

// first make sure the output port is present, create it if it's not
const string outputPortName(ERSPAN_PORT_PREFIX + sess);
string outputPortUuid;
conn->getOvsdbState().getUuidForName(OvsdbTable::PORT, outputPortName, outputPortUuid);
const string portNamedUuid = "port1";
if (outputPortUuid.empty()) {
// need to create port/interface
OvsdbTransactMessage msg(OvsdbOperation::INSERT, OvsdbTable::PORT);
vector<OvsdbValue> values;
values.emplace_back(outputPortName);
OvsdbValues tdSet(values);
msg.rowData.emplace("name", tdSet);

// uuid-name
msg.externalKey = make_pair("uuid-name", portNamedUuid);

// interfaces
values.clear();
const string named_uuid = "interface1";
values.emplace_back("named-uuid", named_uuid);
OvsdbValues tdSet2(values);
msg.rowData.emplace("interfaces", tdSet2);

// uuid-name
OvsdbTransactMessage msg2(OvsdbOperation::INSERT, OvsdbTable::INTERFACE);
msg2.externalKey = make_pair("uuid-name", named_uuid);

// row entries
// name
values.clear();
values.emplace_back(outputPortName);
OvsdbValues tdSet3(values);
msg2.rowData.emplace("name", tdSet3);

values.clear();
const string typeString("erspan");
OvsdbValue typeData(typeString);
values.push_back(typeData);
OvsdbValues tdSet4(values);
msg2.rowData.emplace("type", tdSet4);

values.clear();
values.emplace_back("erspan_ver", std::to_string(version));
values.emplace_back("remote_ip", remoteIp);
OvsdbValues tdSet5("map", values);
msg2.rowData.emplace("options", tdSet5);

requests.push_back(msg);
requests.push_back(msg2);
} else {
LOG(INFO) << "Using existing output port uuid " << outputPortUuid;
}

OvsdbTransactMessage msg1(OvsdbOperation::INSERT, OvsdbTable::MIRROR);
vector<OvsdbValue> srcPortUuids;
for (auto &srcPort : srcPorts) {
Expand Down Expand Up @@ -367,38 +360,46 @@ namespace opflexagent {
msg1.rowData.emplace("select_dst_port", tdSet2);

// output ports
string outputPortUuid;
conn->getOvsdbState().getUuidForName(OvsdbTable::PORT, ERSPAN_PORT_PREFIX + sess, outputPortUuid);
LOG(INFO) << "output port uuid " << outputPortUuid;

if (!outputPortUuid.empty()) {
vector<OvsdbValue> outputPort;
vector<OvsdbValue> outputPort;
if (outputPortUuid.empty()) {
// port is being newly created in this set of requests
OvsdbValue outPort("named-uuid", portNamedUuid);
outputPort.emplace_back(outPort);
} else {
OvsdbValue outPort("uuid", outputPortUuid);
outputPort.emplace_back(outPort);
OvsdbValues tdSet3(outputPort);
msg1.rowData.emplace("output_port", tdSet3);
}
OvsdbValues tdSet3(outputPort);
msg1.rowData.emplace("output_port", tdSet3);

// name
vector<OvsdbValue> values;
values.emplace_back(sess);
OvsdbValues tdSet4(values);
msg1.rowData.emplace("name", tdSet4);

const string uuid_name = "mirror1";
msg1.externalKey = make_pair("uuid-name", uuid_name);
const string mirrorUuidName = "mirror1";
msg1.externalKey = make_pair("uuid-name", mirrorUuidName);

// msg2
values.clear();
OvsdbTransactMessage msg2(OvsdbOperation::MUTATE, OvsdbTable::BRIDGE);
set<tuple<string, OvsdbFunction, string>> condSet;
condSet.emplace("_uuid", OvsdbFunction::EQ, brUuid);
msg2.conditions = condSet;
values.emplace_back("named-uuid", uuid_name);
values.clear();
values.emplace_back("named-uuid", mirrorUuidName);
OvsdbValues tdSet5(values);
msg2.mutateRowData.emplace("mirrors", std::make_pair(OvsdbOperation::INSERT, tdSet5));
// only if we're adding the port now as well
if (outputPortUuid.empty()) {
values.clear();
values.emplace_back("named-uuid", portNamedUuid);
OvsdbValues tdSet6(values);
msg2.mutateRowData.emplace("ports", std::make_pair(OvsdbOperation::INSERT, tdSet6));
}

requests.push_back(msg1);
requests.push_back(msg2);

const list<OvsdbTransactMessage> requests = {msg1, msg2};
sendAsyncTransactRequests(requests);
}
}
14 changes: 0 additions & 14 deletions agent-ovs/ovs/include/OvsdbConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ class OvsdbConnection : public opflex::jsonrpc::RpcConnection {
if (!connected) {
return false;
} else {
LOG(WARNING) << "Check if sync is complete";
unique_lock<mutex> lock(OvsdbConnection::ovsdbMtx);
if (!ready.wait_for(lock, std::chrono::milliseconds(WAIT_TIMEOUT),
[=] { return isSyncComplete(); })) {
Expand Down Expand Up @@ -145,12 +144,6 @@ class OvsdbConnection : public opflex::jsonrpc::RpcConnection {
*/
static void connect_cb(uv_async_t* handle);

/**
* callback for sending requests
* @param[in] handle pointer to uv_async_t
*/
static void send_req_cb(uv_async_t* handle);

/**
* callback for sending queued requests
* @param[in] handle pointer to uv_async_t
Expand Down Expand Up @@ -242,16 +235,9 @@ class OvsdbConnection : public opflex::jsonrpc::RpcConnection {
}

yajr::Peer* peer;

typedef struct req_cb_data_ {
shared_ptr<OvsdbMessage> req;
yajr::Peer* peer;
} req_cb_data;

uv_loop_t* client_loop;
opflex::util::ThreadManager threadManager;
uv_async_t connect_async;
uv_async_t send_req_async;
uv_async_t writeq_async;
std::atomic<bool> connected;
std::atomic<bool> syncComplete;
Expand Down
23 changes: 5 additions & 18 deletions agent-ovs/ovs/include/SpanRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,31 +64,18 @@ class SpanRenderer : public SpanListener,
* @param[in] session name of mirror
* @param[in] srcPorts source ports
* @param[in] dstPorts dest ports
* @param[in] ipAddr remote destination
* @param[in] version erspan version
*/
void createMirror(const string& session, const set<string>& srcPorts, const set<string>& dstPorts);
void createMirrorAndOutputPort(const string& session, const set<string>& srcPorts,
const set<string>& dstPorts, const string& remoteIp, const uint8_t version);

/**
* deletes mirror session
* @param[in] session name of session
* @return true if success, false otherwise.
*/
void deleteMirror(const string& session);

/**
* add port used for erspan
* @param portName erspan port name
* @param ipAddr remote destination
* @param version erspan version
* @return true if success, false otherwise.
*/
void addErspanPort(const string& portName, const string& ipAddr, const uint8_t version);

/**
* delete port used for erspan
* @param name port name
* @return true if success, false otherwise.
*/
void deleteErspanPort(const string& name);
void deleteMirrorAndOutputPort(const string& session);

private:
/**
Expand Down
Loading

0 comments on commit a153321

Please sign in to comment.