Skip to content

Commit

Permalink
Add fat flow support
Browse files Browse the repository at this point in the history
* Maintain a list of protocol and port specified as fat flow
  Ignore flow matching protocol + port combination.
Fixes-Bug: #1518234,#1522285

Change-Id: I6e98b68467f36f1a91227a811f7860c71aaff411
  • Loading branch information
naveen-n committed Dec 28, 2015
1 parent 9e91f9e commit 9c10d20
Show file tree
Hide file tree
Showing 15 changed files with 399 additions and 5 deletions.
23 changes: 23 additions & 0 deletions src/schema/vnc_cfg.xsd
Expand Up @@ -1062,6 +1062,29 @@ targetNamespace="http://www.contrailsystems.com/2012/VNC-CONFIG/0">
ListProperty('virtual-machine-interface-bindings',
'virtual-machine-interface') -->

<xsd:complexType name="ProtocolType">
<xsd:all>
<xsd:element name="protocol" type="xsd:string"/>
<xsd:element name="port" type="xsd:integer"/>
</xsd:all>
</xsd:complexType>

<xsd:complexType name="FatFlowProtocols">
<xsd:all>
<xsd:element name="fat-flow-protocol" type="ProtocolType" maxOccurs="unbounded"/>
</xsd:all>
</xsd:complexType>

<!--
The protocols for which flows on the virtual-machine-interface fall
into a single protocol flow
-->
<xsd:element name="virtual-machine-interface-fat-flow-protocols"
type="FatFlowProtocols"/>
<!--#IFMAP-SEMANTICS-IDL
Property('virtual-machine-interface-fat-flow-protocols',
'virtual-machine-interface') -->

<xsd:element name="virtual-machine-interface-sub-interface"/>
<!--#IFMAP-SEMANTICS-IDL
Link('virtual-machine-interface-sub-interface',
Expand Down
21 changes: 21 additions & 0 deletions src/vnsw/agent/cmn/agent.cc
Expand Up @@ -657,6 +657,27 @@ void Agent::SetAgentMcastLabelRange(uint8_t idx) {
label_range_[idx] = str.str();
}

uint16_t
Agent::ProtocolStringToInt(const std::string &proto) {
if (proto == "tcp" || proto == "TCP") {
return IPPROTO_TCP;
}

if (proto == "udp" || proto == "UDP") {
return IPPROTO_UDP;
}

if (proto == "sctp" || proto == "SCTP") {
return IPPROTO_SCTP;
}

if (proto =="icmp" || proto == "ICMP") {
return IPPROTO_ICMP;
}

return atoi(proto.c_str());
}

Agent::ForwardingMode Agent::TranslateForwardingMode
(const std::string &mode) const {
if (mode == "l2")
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/cmn/agent.h
Expand Up @@ -7,6 +7,7 @@

#include <vector>
#include <stdint.h>
#include <string>
#include <net/ethernet.h>
#include <boost/intrusive_ptr.hpp>
#include <base/intrusive_ptr_back_ref.h>
Expand Down Expand Up @@ -934,6 +935,7 @@ class Agent {
}
Agent::ForwardingMode TranslateForwardingMode(const std::string &mode) const;

static uint16_t ProtocolStringToInt(const std::string &str);
private:

AgentParam *params_;
Expand Down
75 changes: 75 additions & 0 deletions src/vnsw/agent/oper/test/test_intf.cc
Expand Up @@ -170,6 +170,19 @@ class IntfTest : public ::testing::Test {
client->WaitForIdle();
}

void AddFatFlow(struct PortInfo *input, std::string protocol, int port) {

ostringstream str;

str << "<virtual-machine-interface-fat-flow-protocols>"
"<fat-flow-protocol>"
"<protocol>" << protocol << "</protocol>"
"<port>" << port << "</port>"
"</fat-flow-protocol>"
"</virtual-machine-interface-fat-flow-protocols>";
AddNode("virtual-machine-interface", input[0].name, input[0].intf_id,
str.str().c_str());
}

unsigned int intf_count;
Agent *agent;
Expand Down Expand Up @@ -3451,6 +3464,68 @@ TEST_F(IntfTest, Add_vmi_with_zero_mac_and_update_with_correct_mac) {
client->Reset();
}

TEST_F(IntfTest, FatFlow) {
struct PortInfo input[] = {
{"vnet1", 1, "1.1.1.1", "00:00:00:00:00:01", 1, 1},
};

CreateVmportEnv(input, 1);
client->WaitForIdle();
EXPECT_TRUE(VmPortFind(1));

const VmInterface *intf = static_cast<const VmInterface *>(VmPortGet(1));
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 0);

AddFatFlow(input, "udp", 53);
client->WaitForIdle();
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 1);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 53) == true);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 0) == false);

DelNode("virtual-machine-interface", "vnet1");
client->WaitForIdle();
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 0);

DeleteVmportEnv(input, 1, true);
client->WaitForIdle();
EXPECT_FALSE(VmPortFind(1));
client->Reset();
}

TEST_F(IntfTest, FatFlowDel) {
struct PortInfo input[] = {
{"vnet1", 1, "1.1.1.1", "00:00:00:00:00:01", 1, 1},
};

CreateVmportEnv(input, 1);
client->WaitForIdle();
EXPECT_TRUE(VmPortFind(1));

const VmInterface *intf = static_cast<const VmInterface *>(VmPortGet(1));
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 0);

AddFatFlow(input, "udp", 53);
client->WaitForIdle();
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 1);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 53) == true);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 0) == false);

CreateVmportEnv(input, 1);
client->WaitForIdle();
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 0);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 53) == false);
EXPECT_TRUE(intf->IsFatFlow(IPPROTO_UDP, 0) == false);

DelNode("virtual-machine-interface", "vnet1");
client->WaitForIdle();
EXPECT_TRUE(intf->fat_flow_list().list_.size() == 0);

DeleteVmportEnv(input, 1, true);
client->WaitForIdle();
EXPECT_FALSE(VmPortFind(1));
client->Reset();
}

int main(int argc, char **argv) {
GETUSERARGS();

Expand Down
66 changes: 63 additions & 3 deletions src/vnsw/agent/oper/vm_interface.cc
Expand Up @@ -61,7 +61,7 @@ VmInterface::VmInterface(const boost::uuids::uuid &uuid) :
tx_vlan_id_(kInvalidVlanId), rx_vlan_id_(kInvalidVlanId), parent_(NULL),
local_preference_(VmInterface::INVALID), oper_dhcp_options_(),
sg_list_(), floating_ip_list_(), service_vlan_list_(), static_route_list_(),
allowed_address_pair_list_(), vrf_assign_rule_list_(),
allowed_address_pair_list_(), fat_flow_list_(), vrf_assign_rule_list_(),
vrf_assign_acl_(NULL), vm_ip_service_addr_(0),
device_type_(VmInterface::DEVICE_TYPE_INVALID),
vmi_type_(VmInterface::VMI_TYPE_INVALID),
Expand Down Expand Up @@ -415,6 +415,18 @@ static void BuildVrfAndServiceVlanInfo(Agent *agent,
return;
}

static void BuildFatFlowTable(Agent *agent, VmInterfaceConfigData *data,
IFMapNode *node) {
VirtualMachineInterface *cfg = static_cast <VirtualMachineInterface *>
(node->GetObject());
for (FatFlowProtocols::const_iterator it = cfg->fat_flow_protocols().begin();
it != cfg->fat_flow_protocols().end(); it++) {
uint16_t protocol = Agent::ProtocolStringToInt(it->protocol);
data->fat_flow_list_.list_.insert(VmInterface::FatFlowEntry(protocol,
it->port));
}
}

static void BuildInstanceIp(Agent *agent, VmInterfaceConfigData *data,
IFMapNode *node) {
InstanceIp *ip = static_cast<InstanceIp *>(node->GetObject());
Expand Down Expand Up @@ -798,6 +810,14 @@ bool VmInterface::IsConfigurerSet(VmInterface::Configurer type) {
return ((configurer_ & (1 << type)) != 0);
}

bool VmInterface::IsFatFlow(uint8_t protocol, uint16_t port) const {
if (fat_flow_list_.list_.find(FatFlowEntry(protocol, port)) !=
fat_flow_list_.list_.end()) {
return true;
}
return false;
}

static bool DeleteVmi(InterfaceTable *table, const uuid &u, DBRequest *req) {
int type = table->GetVmiToVmiType(u);
if (type <= (int)VmInterface::VMI_TYPE_INVALID)
Expand Down Expand Up @@ -923,6 +943,7 @@ bool InterfaceTable::VmiProcessConfig(IFMapNode *node, DBRequest &req,
}

UpdateAttributes(agent_, data);
BuildFatFlowTable(agent_, data, node);

// Get DHCP enable flag from subnet
if (vn_node && data->addr_.to_ulong()) {
Expand Down Expand Up @@ -1332,10 +1353,13 @@ void VmInterface::ApplyConfigCommon(const VrfEntry *old_vrf,
//DHCP MAC IP binding
ApplyMacVmBindingConfig(old_vrf, old_l2_active, old_dhcp_enable);
//Security Group update
if (IsActive())
if (IsActive()) {
UpdateSecurityGroup();
else
UpdateFatFlow();
} else {
DeleteSecurityGroup();
DeleteFatFlow();
}

}

Expand Down Expand Up @@ -1731,6 +1755,16 @@ bool VmInterface::CopyConfig(const InterfaceTable *table,
ret = true;
}

FatFlowEntrySet &old_fat_flow_entry_list = fat_flow_list_.list_;
const FatFlowEntrySet &new_fat_flow_entry_list =
data->fat_flow_list_.list_;
if (AuditList<FatFlowList, FatFlowEntrySet::iterator>
(fat_flow_list_, old_fat_flow_entry_list.begin(),
old_fat_flow_entry_list.end(), new_fat_flow_entry_list.begin(),
new_fat_flow_entry_list.end())) {
ret = true;
}

InstanceIpSet &old_ipv4_list = instance_ipv4_list_.list_;
InstanceIpSet new_ipv4_list = data->instance_ipv4_list_.list_;
//Native ip of instance should be advertised even if
Expand Down Expand Up @@ -2881,6 +2915,20 @@ void VmInterface::DeleteSecurityGroup() {
}
}

void VmInterface::UpdateFatFlow() {
DeleteFatFlow();
}

void VmInterface::DeleteFatFlow() {
FatFlowEntrySet::iterator it = fat_flow_list_.list_.begin();
while (it != fat_flow_list_.list_.end()) {
FatFlowEntrySet::iterator prev = it++;
if (prev->del_pending_) {
fat_flow_list_.list_.erase(prev);
}
}
}

void VmInterface::UpdateL2TunnelId(bool force_update, bool policy_change) {
AllocL2MplsLabel(force_update, policy_change);
}
Expand Down Expand Up @@ -3270,6 +3318,18 @@ void VmInterface::InstanceIpList::Remove(InstanceIpSet::iterator &it) {
it->set_del_pending(true);
}

void VmInterface::FatFlowList::Insert(const FatFlowEntry *rhs) {
list_.insert(*rhs);
}

void VmInterface::FatFlowList::Update(const FatFlowEntry *lhs,
const FatFlowEntry *rhs) {
}

void VmInterface::FatFlowList::Remove(FatFlowEntrySet::iterator &it) {
it->set_del_pending(true);
}

/////////////////////////////////////////////////////////////////////////////
// FloatingIp routines
/////////////////////////////////////////////////////////////////////////////
Expand Down
46 changes: 46 additions & 0 deletions src/vnsw/agent/oper/vm_interface.h
Expand Up @@ -359,6 +359,43 @@ class VmInterface : public Interface {
InstanceIpSet list_;
};

struct FatFlowEntry : ListEntry {
FatFlowEntry(): protocol(0), port(0) {}
FatFlowEntry(const FatFlowEntry &rhs):
protocol(rhs.protocol), port(rhs.port) {}
FatFlowEntry(const uint8_t proto, const uint16_t p):
protocol(proto), port(p) {}
virtual ~FatFlowEntry(){}
bool operator == (const FatFlowEntry &rhs) const {
return (rhs.protocol == protocol && rhs.port == port);
}

bool operator() (const FatFlowEntry &lhs,
const FatFlowEntry &rhs) const {
return lhs.IsLess(&rhs);
}

bool IsLess(const FatFlowEntry *rhs) const {
if (protocol != rhs->protocol) {
return protocol < rhs->protocol;
}
return port < rhs->port;
}
uint8_t protocol;
uint16_t port;
};
typedef std::set<FatFlowEntry, FatFlowEntry> FatFlowEntrySet;

struct FatFlowList {
FatFlowList(): list_() {}
~FatFlowList() {}
void Insert(const FatFlowEntry *rhs);
void Update(const FatFlowEntry *lhs, const FatFlowEntry *rhs);
void Remove(FatFlowEntrySet::iterator &it);

FatFlowEntrySet list_;
};

enum Trace {
ADD,
DELETE,
Expand Down Expand Up @@ -477,6 +514,11 @@ class VmInterface : public Interface {
return instance_ipv6_list_;
}

const FatFlowList &fat_flow_list() const {
return fat_flow_list_;
}

bool IsFatFlow(uint8_t protocol, uint16_t port) const;
void set_vxlan_id(int vxlan_id) { vxlan_id_ = vxlan_id; }
void set_subnet_bcast_addr(const Ip4Address &addr) {
subnet_bcast_addr_ = addr;
Expand Down Expand Up @@ -678,6 +720,8 @@ class VmInterface : public Interface {
void DeleteAllowedAddressPair(bool l2);
void UpdateSecurityGroup();
void DeleteSecurityGroup();
void UpdateFatFlow();
void DeleteFatFlow();
void UpdateL2TunnelId(bool force_update, bool policy_change);
void DeleteL2TunnelId();
void DeleteL2InterfaceRoute(bool old_l2_active, VrfEntry *old_vrf,
Expand Down Expand Up @@ -748,6 +792,7 @@ class VmInterface : public Interface {
AllowedAddressPairList allowed_address_pair_list_;
InstanceIpList instance_ipv4_list_;
InstanceIpList instance_ipv6_list_;
FatFlowList fat_flow_list_;

// Peer for interface routes
std::auto_ptr<LocalVmPortPeer> peer_;
Expand Down Expand Up @@ -908,6 +953,7 @@ struct VmInterfaceConfigData : public VmInterfaceData {
VmInterface::AllowedAddressPairList allowed_address_pair_list_;
VmInterface::InstanceIpList instance_ipv4_list_;
VmInterface::InstanceIpList instance_ipv6_list_;
VmInterface::FatFlowList fat_flow_list_;
VmInterface::DeviceType device_type_;
VmInterface::VmiType vmi_type_;
// Parent physical-interface. Used in VMWare/ ToR logical-interface
Expand Down

0 comments on commit 9c10d20

Please sign in to comment.