Skip to content

Commit

Permalink
Add support for l3 mode in agent.
Browse files Browse the repository at this point in the history
There are three forwarding modes at VN level and global level-
l2_l3(IRB), l3 only(v4+v6), l2 only.
VN level configuration is always at highest priority.
In case VN level forwarding mode is not configured then global
mode is consulted.

For multicast store the knowledge of bridging enabled in local peer path. This
helps in identifying if EVPN/TOR subscription/withdraw needs to be sent.

Partial-Bug: 1471637
(cherry picked from commit c87a0cf)

Conflicts:
	src/vnsw/agent/oper/vn.cc
	src/vnsw/agent/oper/vn.h

Change-Id: I03f5a883f39c7bc47f7adb8feb1cef949e746755
  • Loading branch information
manishsing committed Aug 7, 2015
1 parent 0e0ee2f commit 6b46e72
Show file tree
Hide file tree
Showing 39 changed files with 1,234 additions and 375 deletions.
12 changes: 12 additions & 0 deletions src/vnsw/agent/cmn/agent.cc
Expand Up @@ -664,3 +664,15 @@ void Agent::SetAgentMcastLabelRange(uint8_t idx) {
mpls_table_->ReserveLabel(start, end + 1);
label_range_[idx] = str.str();
}

Agent::ForwardingMode Agent::TranslateForwardingMode
(const std::string &mode) const {
if (mode == "l2")
return Agent::L2;
else if (mode == "l3")
return Agent::L3;
else if (mode == "l2_l3")
return Agent::L2_L3;

return Agent::NONE;
}
8 changes: 8 additions & 0 deletions src/vnsw/agent/cmn/agent.h
Expand Up @@ -201,6 +201,13 @@ class Agent {
static const uint32_t kMaxOtherOpenFds = 64;
// default timeout zero means, this timeout is not used
static const uint32_t kDefaultFlowCacheTimeout = 0;
enum ForwardingMode {
NONE,
L2_L3,
L2,
L3
};

enum VxLanNetworkIdentifierMode {
AUTOMATIC,
CONFIGURED
Expand Down Expand Up @@ -931,6 +938,7 @@ class Agent {
std::string vrouter_build_info() const {
return vrouter_build_info_;
}
Agent::ForwardingMode TranslateForwardingMode(const std::string &mode) const;

private:

Expand Down
238 changes: 129 additions & 109 deletions src/vnsw/agent/controller/controller_export.cc
Expand Up @@ -79,8 +79,10 @@ void RouteExport::ManagedDelete() {
// Route entry add/change/del notification handler
void RouteExport::Notify(const Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
bool associate, Agent::RouteTableType type,
DBTablePartBase *partition, DBEntryBase *e) {
bool associate,
Agent::RouteTableType type,
DBTablePartBase *partition,
DBEntryBase *e) {
AgentRoute *route = static_cast<AgentRoute *>(e);

// Primitive checks for non-delete notification
Expand Down Expand Up @@ -229,29 +231,59 @@ static bool RouteCanDissociate(const AgentRoute *route) {
return can_dissociate;
}

void RouteExport::SubscribeFabricMulticast(const Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
AgentRoute *route,
RouteExport::State *state) {
const AgentPath *active_path = GetMulticastExportablePath(agent, route);
//Agent running as tor(simulate_evpn_tor) - dont subscribe
//Route has path with peer OVS_PEER i.e. TOR agent mode - dont subscribe
//Subscribe condition:
//first time subscription or force change
if (!(agent->simulate_evpn_tor()) &&
(active_path->peer()->GetType() != Peer::OVS_PEER) &&
((state->fabric_multicast_exported_ == false) ||
(state->force_chg_ == true))) {
//Sending 255.255.255.255 for fabric tree
state->fabric_multicast_exported_ =
AgentXmppChannel::ControllerSendMcastRouteAdd(bgp_xmpp_peer,
route);
}
}

// Handles subscription of multicast routes.
// Following are the kind of subscription:
// Fabric - For fabric replication tree
// EVPN Ingress replication - For adding compute node in EVPN replication list.
// TOR Ingress replication - For adding in TOR replication list (relevant for
// TSN).
//
// For Tor-agent its a route with tunnel NH and there is no subscription.
void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer,
bool associate,
bool associate,
DBTablePartBase *partition,
DBEntryBase *e) {
Agent *agent = bgp_xmpp_peer->agent();
AgentRoute *route = static_cast<AgentRoute *>(e);
AgentRouteTable *table = static_cast<AgentRouteTable *>
(partition->parent());
State *state = static_cast<State *>(route->GetState(partition->parent(), id_));
bool route_can_be_dissociated = RouteCanDissociate(route);
const Agent *agent = bgp_xmpp_peer->agent();

if (route->GetTableType() != Agent::BRIDGE)
return;
//Currently only bridge flood route is taken, though there is a seperate
//multicast table as well. In future if multicats table is populated, get
//rid of this assert or expand it.
assert(route->GetTableType() == Agent::BRIDGE);

if (route_can_be_dissociated && (state != NULL)) {
if ((state->exported_ == true) && !(agent->simulate_evpn_tor())) {
//Handle withdraw for following cases:
//- Route is not having any active multicast exportable path or is deleted.
//- associate(false): Bgp Peer has gone down and state needs to be removed.
if ((route_can_be_dissociated || !associate) && (state != NULL)) {
if (state->fabric_multicast_exported_ == true) {
AgentXmppChannel::ControllerSendMcastRouteDelete(bgp_xmpp_peer,
route);
state->exported_ = false;
state->fabric_multicast_exported_ = false;
}

if ((route->GetTableType() == Agent::BRIDGE) &&
(state->fabric_multicast_exported_ == true)) {
if ((state->ingress_replication_exported_ == true)) {
state->tunnel_type_ = TunnelType::INVALID;
AgentXmppChannel::ControllerSendEvpnRouteDelete(bgp_xmpp_peer,
route,
Expand All @@ -260,7 +292,7 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer,
state->destination_,
state->source_,
TunnelType::AllType());
state->fabric_multicast_exported_ = false;
state->ingress_replication_exported_ = false;
}

route->ClearState(partition->parent(), id_);
Expand All @@ -269,14 +301,6 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer,
return;
}

if (route->IsDeleted()) {
if (state) {
route->ClearState(partition->parent(), id_);
delete state;
}
return;
}

if (marked_delete_) {
//Ignore route updates on delete marked vrf
return;
Expand All @@ -287,101 +311,97 @@ void RouteExport::MulticastNotify(AgentXmppChannel *bgp_xmpp_peer,
route->SetState(partition->parent(), id_, state);
}

if (!route_can_be_dissociated) {
const AgentPath *active_path = GetMulticastExportablePath(agent, route);
if (!(agent->simulate_evpn_tor()) &&
(active_path->peer()->GetType() != Peer::OVS_PEER) &&
((state->exported_ == false) || (state->force_chg_ == true))) {
//Sending 255.255.255.255 for fabric tree
if (associate) {
state->exported_ =
AgentXmppChannel::ControllerSendMcastRouteAdd(bgp_xmpp_peer,
route);
} else {
AgentXmppChannel::ControllerSendMcastRouteDelete(bgp_xmpp_peer,
route);
SubscribeFabricMulticast(agent, bgp_xmpp_peer, route, state);
SubscribeIngressReplication(agent, bgp_xmpp_peer, route, state);

state->force_chg_ = false;
return;
}

void RouteExport::SubscribeIngressReplication(Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
AgentRoute *route,
RouteExport::State *state) {
//Check if bridging mode is enabled for this VN by verifying bridge flag
//in local peer path.
bool bridging = false;
if (route->vrf() && route->vrf()->vn() && route->vrf()->vn()->bridging())
bridging = true;

const AgentPath *active_path = GetMulticastExportablePath(agent, route);
//Sending ff:ff:ff:ff:ff:ff for evpn replication
TunnelType::Type old_tunnel_type = state->tunnel_type_;
uint32_t old_label = state->label_;
TunnelType::Type new_tunnel_type = active_path->tunnel_type();
uint32_t new_label = active_path->GetActiveLabel();

//Evaluate if ingress replication subscription needs to be withdrawn.
//Conditions: Tunnel type changed (VXLAN to MPLS) in turn label change,
//bridging is disabled/enabled on VN
if ((state->ingress_replication_exported_ == true) ||
(state->force_chg_ == true)) {
bool withdraw = false;
uint32_t withdraw_label = 0;

if (old_tunnel_type == TunnelType::VXLAN) {
if ((new_tunnel_type != TunnelType::VXLAN) ||
(old_label != new_label)) {
withdraw_label = old_label;
withdraw = true;
}
} else if (new_tunnel_type == TunnelType::VXLAN) {
withdraw = true;
}

//Sending ff:ff:ff:ff:ff:ff for evpn replication
//const AgentPath *active_path = route->GetActivePath();
TunnelType::Type old_tunnel_type = state->tunnel_type_;
uint32_t old_label = state->label_;
TunnelType::Type new_tunnel_type = active_path->tunnel_type();
uint32_t new_label = active_path->GetActiveLabel();

if (route->GetTableType() == Agent::BRIDGE) {
if ((state->fabric_multicast_exported_ == true) || (state->force_chg_ ==
true)) {
bool withdraw = false;
uint32_t withdraw_label = 0;

if (old_tunnel_type == TunnelType::VXLAN) {
if ((new_tunnel_type != TunnelType::VXLAN) ||
(old_label != new_label)) {
withdraw_label = old_label;
withdraw = true;
}
} else if (new_tunnel_type == TunnelType::VXLAN) {
withdraw = true;
}
if (withdraw) {
AgentXmppChannel::ControllerSendEvpnRouteDelete
(bgp_xmpp_peer, route, state->vn_, withdraw_label,
state->destination_, state->source_,
state->tunnel_type_);
state->fabric_multicast_exported_ = false;
}
}
if (bridging == false)
withdraw = true;

if (active_path) {
if (active_path->tunnel_type() != state->tunnel_type_) {
state->force_chg_ = true;
state->tunnel_type_ = active_path->tunnel_type();
}
if (withdraw) {
AgentXmppChannel::ControllerSendEvpnRouteDelete
(bgp_xmpp_peer, route, state->vn_, withdraw_label,
state->destination_, state->source_,
state->tunnel_type_);
state->ingress_replication_exported_ = false;
}
}

if (active_path->GetActiveLabel() != state->label_) {
state->force_chg_ = true;
state->label_ = active_path->GetActiveLabel();
}
}
//Update state values with new values if there is any change.
//Also force change same i.e. update.
if (active_path->tunnel_type() != state->tunnel_type_) {
state->force_chg_ = true;
state->tunnel_type_ = active_path->tunnel_type();
}

if ((state->fabric_multicast_exported_ == false) || (state->force_chg_
== true)) {
state->label_ = active_path->GetActiveLabel();
state->vn_ = route->dest_vn_name();
if (associate) {
const TunnelNH *tnh =
dynamic_cast<const TunnelNH *>(active_path->nexthop());
if (tnh) {
state->destination_ = tnh->GetDip()->to_string();
state->source_ = tnh->GetSip()->to_string();
}

SecurityGroupList sg;
state->fabric_multicast_exported_ =
AgentXmppChannel::ControllerSendEvpnRouteAdd
(bgp_xmpp_peer, route,
active_path->NexthopIp(table->agent()),
route->dest_vn_name(), state->label_,
TunnelType::GetTunnelBmap(state->tunnel_type_),
&sg, state->destination_,
state->source_, PathPreference());
} else {
state->fabric_multicast_exported_ =
AgentXmppChannel::ControllerSendEvpnRouteDelete(bgp_xmpp_peer,
route,
route->dest_vn_name(),
state->label_,
state->destination_,
state->source_,
TunnelType::AllType());
}
}
if (active_path->GetActiveLabel() != state->label_) {
state->force_chg_ = true;
state->label_ = active_path->GetActiveLabel();
}

//Subcribe if:
//- Bridging is enabled
//- First time (ingress_replication_exported is false)
//- Forced Change
if (bridging &&
((state->ingress_replication_exported_ == false) ||
(state->force_chg_ == true))) {
state->label_ = active_path->GetActiveLabel();
state->vn_ = route->dest_vn_name();
const TunnelNH *tnh =
dynamic_cast<const TunnelNH *>(active_path->nexthop());
if (tnh) {
state->destination_ = tnh->GetDip()->to_string();
state->source_ = tnh->GetSip()->to_string();
}

state->force_chg_ = false;
return;
SecurityGroupList sg;
state->ingress_replication_exported_ =
AgentXmppChannel::ControllerSendEvpnRouteAdd
(bgp_xmpp_peer, route,
active_path->NexthopIp(agent),
route->dest_vn_name(), state->label_,
TunnelType::GetTunnelBmap(state->tunnel_type_),
&sg, state->destination_,
state->source_, PathPreference());
}
}

Expand Down
20 changes: 16 additions & 4 deletions src/vnsw/agent/controller/controller_export.h
Expand Up @@ -20,6 +20,7 @@ class RouteExport {
virtual ~State() {};

bool exported_;
bool ingress_replication_exported_; //Used by multicast
bool fabric_multicast_exported_; //Used by multicast
bool force_chg_;
uint32_t label_;
Expand All @@ -37,9 +38,12 @@ class RouteExport {
RouteExport(AgentRouteTable *rt);
~RouteExport();

void Notify(const Agent *agent, AgentXmppChannel *bgp_xmpp_peer,
bool associate, Agent::RouteTableType type,
DBTablePartBase *partition, DBEntryBase *e);
void Notify(const Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
bool associate,
Agent::RouteTableType type,
DBTablePartBase *partition,
DBEntryBase *e);
void ManagedDelete();
DBTableBase::ListenerId GetListenerId() const {return id_;};
void Unregister();
Expand All @@ -53,11 +57,19 @@ class RouteExport {
AgentRouteTable *rt_table_;
bool marked_delete_;
uint32_t state_added_;
void MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, bool associate,
void MulticastNotify(AgentXmppChannel *bgp_xmpp_peer, bool associate,
DBTablePartBase *partition, DBEntryBase *e);
void UnicastNotify(AgentXmppChannel *bgp_xmpp_peer,
DBTablePartBase *partition, DBEntryBase *e,
Agent::RouteTableType type);
void SubscribeFabricMulticast(const Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
AgentRoute *route,
RouteExport::State *state);
void SubscribeIngressReplication(Agent *agent,
AgentXmppChannel *bgp_xmpp_peer,
AgentRoute *route,
RouteExport::State *state);
LifetimeRef<RouteExport> table_delete_ref_;
};

Expand Down
9 changes: 5 additions & 4 deletions src/vnsw/agent/kstate/test/test_kstate.cc
Expand Up @@ -123,8 +123,9 @@ class KStateTest : public ::testing::Test {
//5 interface nexthops get created for each interface
//(l2 with policy, l2 without policy, l3 with policy, l3
// without policy and 1 multicast - mac as all f's)
//plus 4 Nexthops for each VRF (1 VRF NH and 2 Composite NHs)
WAIT_FOR(1000, 1000, ((nh_count + (num_ports * 5) + 3) ==
//plus 4 Nexthops for each VRF (1 VRF NH and 3 Composite NHs
//i.e. TOR CNH, EVPN CNH, Fabric CNH)
WAIT_FOR(1000, 1000, ((nh_count + (num_ports * 5) + 4) ==
(uint32_t)KSyncSockTypeMap::NHCount()));
}
if (rt_count) {
Expand Down Expand Up @@ -259,8 +260,8 @@ TEST_F(KStateTest, NHDumpTest) {
//5 interface nexthops get created for each interface
//(l2 with policy, l2 without policy, l3 with policy, l3 without policy
// and 1 multicast - mac as all f's )
//plus 4 Nexthops for each VRF (1 VRF NH and 2 Composite NHs)
TestNHKState::Init(-1, true, nh_count + (max_ports * 5) + 3);
//plus 4 Nexthops for each VRF (1 VRF NH and 3 Composite NHs)
TestNHKState::Init(-1, true, nh_count + (max_ports * 5) + 4);
client->WaitForIdle();
client->KStateResponseWait(1);

Expand Down

0 comments on commit 6b46e72

Please sign in to comment.