Skip to content

Commit

Permalink
Merge "Fix health-check when fat flow enabled on vmi"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed Apr 5, 2017
2 parents 79152bd + 9c11519 commit 0ce5216
Show file tree
Hide file tree
Showing 14 changed files with 451 additions and 24 deletions.
26 changes: 22 additions & 4 deletions src/vnsw/agent/oper/health_check.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ bool HealthCheckInstance::DestroyInstanceTask() {
void HealthCheckInstance::UpdateInstanceTaskCommand() {
if (service_->table_->agent()->test_mode()) {
// in test mode, set task instance to run no-op shell
task_->set_cmd("/bin/sh");
task_->set_cmd("sleep 1");
return;
}

Expand Down Expand Up @@ -258,11 +258,21 @@ bool HealthCheckService::Copy(HealthCheckTable *table,
ret = true;
}

if (ip_proto_ != data->ip_proto_) {
ip_proto_ = data->ip_proto_;
ret = true;
}

if (url_path_ != data->url_path_) {
url_path_ = data->url_path_;
ret = true;
}

if (url_port_ != data->url_port_) {
url_port_ = data->url_port_;
ret = true;
}

if (expected_codes_ != data->expected_codes_) {
expected_codes_ = data->expected_codes_;
ret = true;
Expand Down Expand Up @@ -441,11 +451,15 @@ static HealthCheckServiceData *BuildData(Agent *agent, IFMapNode *node,
const autogen::ServiceHealthCheckType &p = s->properties();
Ip4Address dest_ip;
std::string url_path;
uint8_t ip_proto = 0;
uint16_t url_port = 0;
if (p.monitor_type.find("HTTP") == std::string::npos) {
boost::system::error_code ec;
dest_ip = Ip4Address::from_string(p.url_path, ec);
url_path = p.url_path;
ip_proto = IPPROTO_ICMP;
} else if (!p.url_path.empty()) {
ip_proto = IPPROTO_TCP;
// parse url if available
struct http_parser_url urldata;
int ret = http_parser_parse_url(p.url_path.c_str(), p.url_path.size(),
Expand All @@ -459,13 +473,17 @@ static HealthCheckServiceData *BuildData(Agent *agent, IFMapNode *node,
// keep rest of the url string as is
url_path = p.url_path.substr(urldata.field_data[UF_HOST].off +\
urldata.field_data[UF_HOST].len);
url_port = urldata.port;
if ((urldata.field_set & (1 << UF_PORT)) == 0) {
url_port = 80;
}
}
}
HealthCheckServiceData *data =
new HealthCheckServiceData(agent, dest_ip, node->name(),
p.monitor_type, p.http_method, url_path,
p.expected_codes, p.delay, p.timeout,
p.max_retries, node);
p.monitor_type, ip_proto, p.http_method,
url_path, url_port, p.expected_codes,
p.delay, p.timeout, p.max_retries, node);

IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
for (DBGraphVertex::adjacency_iterator iter =
Expand Down
25 changes: 21 additions & 4 deletions src/vnsw/agent/oper/health_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,28 @@ struct HealthCheckServiceData : public AgentOperDBData {
HealthCheckServiceData(Agent *agent, IpAddress dest_ip,
const std::string &name,
const std::string &monitor_type,
uint8_t ip_proto,
const std::string &http_method,
const std::string &url_path,
uint16_t url_port,
const std::string &expected_codes,
uint32_t delay, uint32_t timeout,
uint32_t max_retries, IFMapNode *ifmap_node) :
AgentOperDBData(agent, ifmap_node), dest_ip_(dest_ip), name_(name),
monitor_type_(monitor_type), http_method_(http_method),
url_path_(url_path), expected_codes_(expected_codes), delay_(delay),
timeout_(timeout), max_retries_(max_retries) {
monitor_type_(monitor_type), ip_proto_(ip_proto),
http_method_(http_method), url_path_(url_path), url_port_(url_port),
expected_codes_(expected_codes), delay_(delay), timeout_(timeout),
max_retries_(max_retries) {
}
virtual ~HealthCheckServiceData() {}

IpAddress dest_ip_;
std::string name_;
std::string monitor_type_;
uint8_t ip_proto_;
std::string http_method_;
std::string url_path_;
uint16_t url_port_;
std::string expected_codes_;
uint32_t delay_;
uint32_t timeout_;
Expand All @@ -86,7 +91,8 @@ struct HealthCheckInstanceEvent {
DISALLOW_COPY_AND_ASSIGN(HealthCheckInstanceEvent);
};

struct HealthCheckInstance {
class HealthCheckInstance {
public:
typedef InstanceTaskExecvp HeathCheckProcessInstance;
static const std::string kHealthCheckCmd;

Expand Down Expand Up @@ -117,6 +123,11 @@ struct HealthCheckInstance {
bool active() {return active_;}
bool IsRunning() const;

HealthCheckService *service() const { return service_.get(); }
const MetaDataIp *ip() const { return ip_.get(); }
private:
friend class HealthCheckService;
friend class HealthCheckTable;
// reference to health check service under
// which this instance is running
HealthCheckServiceRef service_;
Expand Down Expand Up @@ -165,6 +176,8 @@ class HealthCheckService : AgentRefCount<HealthCheckService>,
const boost::uuids::uuid &uuid() const { return uuid_; }
const std::string &name() const { return name_; }

uint8_t ip_proto() const { return ip_proto_; }
uint16_t url_port() const { return url_port_; }
private:
friend class HealthCheckInstance;
friend class HealthCheckInstanceEvent;
Expand All @@ -175,8 +188,12 @@ class HealthCheckService : AgentRefCount<HealthCheckService>,
std::string name_;
// monitor type of service PING/HTTP etc
std::string monitor_type_;
// ip_proto derived from monitor_type_
uint8_t ip_proto_;
std::string http_method_;
std::string url_path_;
// tcp/udp port numbers derived from url
uint16_t url_port_;
std::string expected_codes_;
uint32_t delay_;
uint32_t timeout_;
Expand Down
10 changes: 3 additions & 7 deletions src/vnsw/agent/oper/metadata_ip.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ MetaDataIp::~MetaDataIp() {
allocator_->ReleaseIndex(this);
}

Ip4Address MetaDataIp::GetLinkLocalIp() {
Ip4Address MetaDataIp::GetLinkLocalIp() const {
uint32_t ip = METADATA_IP_ADDR & 0xFFFF0000;
ip += (((uint32_t)index_) & 0xFFFF);
return Ip4Address(ip);
}

IpAddress MetaDataIp::service_ip() {
IpAddress MetaDataIp::service_ip() const {
// check if explicit configuration of service ip is present for
// this metadata ip
if (service_ip_ == kDefaultIp) {
Expand All @@ -66,11 +66,7 @@ IpAddress MetaDataIp::service_ip() {
return service_ip_;
}

void MetaDataIp::set_service_ip(const IpAddress &src_ip) {
service_ip_ = src_ip;
}

IpAddress MetaDataIp::destination_ip() {
IpAddress MetaDataIp::destination_ip() const {
if (destination_ip_.to_v4() == kDefaultIp) {
return intf_->primary_ip_addr();
}
Expand Down
7 changes: 3 additions & 4 deletions src/vnsw/agent/oper/metadata_ip.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,11 @@ class MetaDataIp {
uint16_t index);
~MetaDataIp();

Ip4Address GetLinkLocalIp();
Ip4Address GetLinkLocalIp() const;

IpAddress service_ip();
void set_service_ip(const IpAddress &src_ip);
IpAddress service_ip() const;

IpAddress destination_ip();
IpAddress destination_ip() const;
void set_destination_ip(const IpAddress &dst_ip);

void set_active(bool active);
Expand Down
43 changes: 43 additions & 0 deletions src/vnsw/agent/oper/vm_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5540,6 +5540,49 @@ VmInterface::hc_instance_set() const {
return hc_instance_set_;
}

bool VmInterface::IsHealthCheckEnabled() const {
return hc_instance_set_.size() != 0;
}

// Match the Health-Check instance for a packet from VM-Interface
// A packet from vmi is assumed to be response for health-check request from
// vhost0
const HealthCheckInstance *VmInterface::GetHealthCheckFromVmiFlow
(const IpAddress &sip, const IpAddress &dip, uint8_t proto,
uint16_t sport) const {
HealthCheckInstanceSet::const_iterator it = hc_instance_set_.begin();
while (it != hc_instance_set_.end()) {
const HealthCheckInstance *hc_instance = *it;
it++;

// Match ip-proto and health-check port
const HealthCheckService *hc_service = hc_instance->service();
if (hc_service == NULL)
continue;

if (hc_service->ip_proto() != proto)
continue;

if (hc_service->url_port() != sport)
continue;

// The source-ip and destination-ip can be matched from MetaDataIp
// allocated for HealthCheck
const MetaDataIp *mip = hc_instance->ip();
if (mip == NULL)
continue;

if (mip->destination_ip() != sip)
continue;

if (mip->service_ip() != dip)
continue;

return hc_instance;
}

return NULL;
}
////////////////////////////////////////////////////////////////////////////
// VRF assign rule routines
////////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 5 additions & 1 deletion src/vnsw/agent/oper/vm_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,11 @@ class VmInterface : public Interface {
void InsertHealthCheckInstance(HealthCheckInstance *hc_inst);
void DeleteHealthCheckInstance(HealthCheckInstance *hc_inst);
const HealthCheckInstanceSet &hc_instance_set() const;

bool IsHealthCheckEnabled() const;
const HealthCheckInstance *GetHealthCheckFromVmiFlow(const IpAddress &sip,
const IpAddress &dip,
uint8_t proto,
uint16_t sport) const;
size_t GetFloatingIpCount() const { return floating_ip_list_.list_.size(); }
size_t GetAliasIpCount() const { return alias_ip_list_.list_.size(); }
bool HasServiceVlan() const { return service_vlan_list_.list_.size() != 0; }
Expand Down
53 changes: 53 additions & 0 deletions src/vnsw/agent/pkt/pkt_flow_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "oper/operdb_init.h"
#include "oper/tunnel_nh.h"
#include "oper/bgp_as_service.h"
#include "oper/health_check.h"

#include "filter/packet_header.h"
#include "filter/acl.h"
Expand Down Expand Up @@ -770,6 +771,53 @@ void PktFlowInfo::BgpRouterServiceTranslate(const PktInfo *pkt,
}
}

// Consider Health Check is enabled on an interface and also FAT flow is
// enabled for the destination port.
//
// VRouter receives request from vhost0 interface. The vhost0 interface does
// not have fat-flow enabled, so 5-tuple flow is created ignoring the fat flow
//
// VRouter receives response from vm-interface that has fat-flow enabled.
// So, VRouter creates with fat-flow. Agent needs to ensure that fat flow
// created must do the NAT translation according to health-check rules
//
// Note, if FAT flow is not configured, then pacekt from vm-interface will
// hit the reverse flow created due to request
void PktFlowInfo::ProcessHealthCheckFatFlow(const VmInterface *vmi,
const PktInfo *pkt,
PktControlInfo *in,
PktControlInfo *out) {
// Health check valid for IPv4 only
if (pkt->ip_daddr.is_v4() == false || pkt->ip_saddr.is_v4() == false)
return;

// Ensure fat-flow is configured for the port first
if (vmi->IsFatFlow(pkt->ip_proto, pkt->sport) == false)
return;

// Look for health-check rule
const HealthCheckInstance *hc_instance =
vmi->GetHealthCheckFromVmiFlow(pkt->ip_saddr, pkt->ip_daddr,
pkt->ip_proto, pkt->sport);
if (hc_instance == NULL)
return;

const MetaDataIp *mip = hc_instance->ip();
if (mip == NULL)
return;

nat_done = true;
nat_ip_saddr = mip->GetLinkLocalIp();
nat_ip_daddr = agent->router_id();
nat_dport = pkt->dport;
nat_sport = pkt->sport;
nat_vrf = agent->fabric_vrf()->vrf_id();
nat_dest_vrf = dest_vrf;
dest_vrf = agent->fabric_vrf()->vrf_id();
return;
}


// DestNAT for packets entering into a VM with floating-ip.
// Can come here in two paths,
// - Packet originated on local vm.
Expand Down Expand Up @@ -1184,6 +1232,11 @@ void PktFlowInfo::IngressProcess(const PktInfo *pkt, PktControlInfo *in,
BgpRouterServiceTranslate(pkt, in, out);
}

// Handle special case of health-check with fat-flow
if (vm_port && vm_port->IsHealthCheckEnabled()) {
ProcessHealthCheckFatFlow(vm_port, pkt, in, out);
}

// If out-interface was not found, get it based on out-route
if (out->intf_ == NULL && out->rt_) {
RouteToOutInfo(out->rt_, pkt, this, in, out);
Expand Down
2 changes: 2 additions & 0 deletions src/vnsw/agent/pkt/pkt_flow_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ class PktFlowInfo {
PktControlInfo *out);
void BgpRouterServiceTranslate(const PktInfo *pkt, PktControlInfo *in,
PktControlInfo *out);
void ProcessHealthCheckFatFlow(const VmInterface *vmi, const PktInfo *pkt,
PktControlInfo *in, PktControlInfo *out);
void FloatingIpSNat(const PktInfo *pkt, PktControlInfo *in,
PktControlInfo *out);
void FloatingIpDNat(const PktInfo *pkt, PktControlInfo *in,
Expand Down
1 change: 1 addition & 0 deletions src/vnsw/agent/pkt/test/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ test_flow_mgmt_route = AgentEnv.MakeTestCmd(env, 'test_flow_mgmt_route',
pkt_test_suite)
test_tsn_flow = AgentEnv.MakeTestCmd(env, 'test_tsn_flow', pkt_test_suite)
test_flow_table = AgentEnv.MakeTestCmd(env, 'test_flow_table', pkt_test_suite)
test_flow_hc = AgentEnv.MakeTestCmd(env, 'test_flow_hc', pkt_test_suite)
test_pkt = AgentEnv.MakeTestCmd(env, 'test_pkt', pkt_flaky_test_suite)
test_pkt_flow_mock = AgentEnv.MakeTestCmd(env, 'test_pkt_flow_mock',
pkt_flaky_test_suite)
Expand Down

0 comments on commit 0ce5216

Please sign in to comment.