diff --git a/src/vnsw/agent/cmn/agent.cc b/src/vnsw/agent/cmn/agent.cc index f552eb95b5b..31de46fbe88 100644 --- a/src/vnsw/agent/cmn/agent.cc +++ b/src/vnsw/agent/cmn/agent.cc @@ -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; +} diff --git a/src/vnsw/agent/cmn/agent.h b/src/vnsw/agent/cmn/agent.h index 057ead4e3ad..a88aae0f0f6 100644 --- a/src/vnsw/agent/cmn/agent.h +++ b/src/vnsw/agent/cmn/agent.h @@ -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 @@ -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: diff --git a/src/vnsw/agent/controller/controller_export.cc b/src/vnsw/agent/controller/controller_export.cc index a26d7296f74..59783c21d68 100644 --- a/src/vnsw/agent/controller/controller_export.cc +++ b/src/vnsw/agent/controller/controller_export.cc @@ -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(e); // Primitive checks for non-delete notification @@ -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(e); - AgentRouteTable *table = static_cast - (partition->parent()); State *state = static_cast(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, @@ -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_); @@ -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; @@ -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(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(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()); } } diff --git a/src/vnsw/agent/controller/controller_export.h b/src/vnsw/agent/controller/controller_export.h index fc72f80190b..22c1b2f7088 100644 --- a/src/vnsw/agent/controller/controller_export.h +++ b/src/vnsw/agent/controller/controller_export.h @@ -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_; @@ -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(); @@ -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 table_delete_ref_; }; diff --git a/src/vnsw/agent/kstate/test/test_kstate.cc b/src/vnsw/agent/kstate/test/test_kstate.cc index e90d87ca1fc..24a8974345a 100644 --- a/src/vnsw/agent/kstate/test/test_kstate.cc +++ b/src/vnsw/agent/kstate/test/test_kstate.cc @@ -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) { @@ -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); diff --git a/src/vnsw/agent/oper/SConscript b/src/vnsw/agent/oper/SConscript index 7fef260886b..3ac931870e6 100644 --- a/src/vnsw/agent/oper/SConscript +++ b/src/vnsw/agent/oper/SConscript @@ -30,7 +30,7 @@ vnswoperdb = env.Library('vnswoperdb', 'agent_path.cc', 'agent_profile.cc', 'agent_route.cc', - 'agent_route_encap.cc', + 'agent_route_resync.cc', 'agent_route_walker.cc', 'bridge_route.cc', 'config_manager.cc', diff --git a/src/vnsw/agent/oper/agent_path.cc b/src/vnsw/agent/oper/agent_path.cc index 57f6a57bf3f..fefcca9f5d3 100644 --- a/src/vnsw/agent/oper/agent_path.cc +++ b/src/vnsw/agent/oper/agent_path.cc @@ -36,7 +36,7 @@ AgentPath::AgentPath(const Peer *peer, AgentRoute *rt): vrf_name_(""), gw_ip_(0), unresolved_(true), is_stale_(false), is_subnet_discard_(false), dependant_rt_(rt), path_preference_(), local_ecmp_mpls_label_(rt), composite_nh_key_(NULL), subnet_gw_ip_(), - flood_dhcp_(false), arp_mac_(), arp_interface_(NULL), arp_valid_(false) { + arp_mac_(), arp_interface_(NULL), arp_valid_(false) { } AgentPath::~AgentPath() { diff --git a/src/vnsw/agent/oper/agent_path.h b/src/vnsw/agent/oper/agent_path.h index d0e91c215ae..30b6f16e978 100644 --- a/src/vnsw/agent/oper/agent_path.h +++ b/src/vnsw/agent/oper/agent_path.h @@ -197,9 +197,6 @@ class AgentPath : public Path { // Get nexthop-ip address to be used for path const Ip4Address *NexthopIp(Agent *agent) const; - //Flood DHCP - bool flood_dhcp() const {return flood_dhcp_;} - void set_flood_dhcp(bool flood_dhcp) const {flood_dhcp_ = flood_dhcp;} MacAddress arp_mac() const {return arp_mac_;} void set_arp_mac(const MacAddress &mac) { arp_mac_ = mac; @@ -268,8 +265,6 @@ class AgentPath : public Path { //helping in deciding the priority during live migration and //allowed address pair IpAddress subnet_gw_ip_; - // should vrouter flood the DHCP request coming from this source route - mutable bool flood_dhcp_; //Mac address of ARP NH, used to notify change //to routes dependent on mac change, or ageout of ARP MacAddress arp_mac_; @@ -672,12 +667,13 @@ class MacVmBindingPath : public AgentPath { void set_vm_interface(const VmInterface *vm_interface) { vm_interface_ = vm_interface; } - bool flood_dhcp() const {return flood_dhcp_;} + virtual bool flood_dhcp() const {return flood_dhcp_;} void set_flood_dhcp(bool flood_dhcp) {flood_dhcp_ = flood_dhcp;} private: //Key parameters for comparision InterfaceConstRef vm_interface_; + // should vrouter flood the DHCP request coming from this source route bool flood_dhcp_; DISALLOW_COPY_AND_ASSIGN(MacVmBindingPath); }; diff --git a/src/vnsw/agent/oper/agent_route_encap.cc b/src/vnsw/agent/oper/agent_route_resync.cc similarity index 74% rename from src/vnsw/agent/oper/agent_route_encap.cc rename to src/vnsw/agent/oper/agent_route_resync.cc index 0e111821458..43d0dc24269 100644 --- a/src/vnsw/agent/oper/agent_route_encap.cc +++ b/src/vnsw/agent/oper/agent_route_resync.cc @@ -10,22 +10,22 @@ #include #include -#include +#include #include #include #include -AgentRouteEncap::AgentRouteEncap(Agent *agent) : +AgentRouteResync::AgentRouteResync(Agent *agent) : AgentRouteWalker(agent, AgentRouteWalker::ALL) { } -bool AgentRouteEncap::RouteWalkNotify(DBTablePartBase *partition, +bool AgentRouteResync::RouteWalkNotify(DBTablePartBase *partition, DBEntryBase *e) { AgentRoute *route = static_cast(e); route->EnqueueRouteResync(); return true; } -void AgentRouteEncap::Update() { +void AgentRouteResync::Update() { StartVrfWalk(); } diff --git a/src/vnsw/agent/oper/agent_route_encap.h b/src/vnsw/agent/oper/agent_route_resync.h similarity index 60% rename from src/vnsw/agent/oper/agent_route_encap.h rename to src/vnsw/agent/oper/agent_route_resync.h index 89313180703..28dd0465daf 100644 --- a/src/vnsw/agent/oper/agent_route_encap.h +++ b/src/vnsw/agent/oper/agent_route_resync.h @@ -2,24 +2,24 @@ * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. */ -#ifndef vnsw_agent_route_encap_hpp -#define vnsw_agent_route_encap_hpp +#ifndef vnsw_agent_route_resync_hpp +#define vnsw_agent_route_resync_hpp #include #include #include -class AgentRouteEncap : public AgentRouteWalker { +class AgentRouteResync : public AgentRouteWalker { public: typedef DBTableWalker::WalkId RouteWalkerIdList[Agent::ROUTE_TABLE_MAX]; - AgentRouteEncap(Agent *agent); - virtual ~AgentRouteEncap() { } + AgentRouteResync(Agent *agent); + virtual ~AgentRouteResync() { } void Update(); virtual bool RouteWalkNotify(DBTablePartBase *partition, DBEntryBase *e); private: - DISALLOW_COPY_AND_ASSIGN(AgentRouteEncap); + DISALLOW_COPY_AND_ASSIGN(AgentRouteResync); }; #endif diff --git a/src/vnsw/agent/oper/agent_route_walker.cc b/src/vnsw/agent/oper/agent_route_walker.cc index d4827b1970a..2d20c1522d1 100644 --- a/src/vnsw/agent/oper/agent_route_walker.cc +++ b/src/vnsw/agent/oper/agent_route_walker.cc @@ -10,7 +10,6 @@ #include #include -#include #include #include diff --git a/src/vnsw/agent/oper/bridge_route.cc b/src/vnsw/agent/oper/bridge_route.cc index 0127b5e865a..752599cd3bc 100644 --- a/src/vnsw/agent/oper/bridge_route.cc +++ b/src/vnsw/agent/oper/bridge_route.cc @@ -336,8 +336,7 @@ const VmInterface *BridgeAgentRouteTable::FindVmFromDhcpBinding if (l2_rt == NULL) return NULL; - const MacVmBindingPath *dhcp_path = dynamic_cast - (l2_rt->FindMacVmBindingPath()); + const MacVmBindingPath *dhcp_path = l2_rt->FindMacVmBindingPath(); if (dhcp_path == NULL) return NULL; return dhcp_path->vm_interface(); @@ -531,9 +530,9 @@ void BridgeRouteEntry::DeletePathUsingKeyData(const AgentRouteKey *key, } } -const AgentPath *BridgeRouteEntry::FindMacVmBindingPath() const { +const MacVmBindingPath *BridgeRouteEntry::FindMacVmBindingPath() const { Agent *agent = (static_cast (get_table()))->agent(); - return FindPath(agent->mac_vm_binding_peer()); + return dynamic_cast(FindPath(agent->mac_vm_binding_peer())); } const AgentPath *BridgeRouteEntry::FindOvsPath() const { diff --git a/src/vnsw/agent/oper/bridge_route.h b/src/vnsw/agent/oper/bridge_route.h index 82550e879e1..2d1d474f92e 100644 --- a/src/vnsw/agent/oper/bridge_route.h +++ b/src/vnsw/agent/oper/bridge_route.h @@ -5,6 +5,8 @@ #ifndef vnsw_bridge_route_hpp #define vnsw_bridge_route_hpp +class MacVmBindingPath; + ////////////////////////////////////////////////////////////////// // BRIDGE ///////////////////////////////////////////////////////////////// @@ -138,7 +140,7 @@ class BridgeRouteEntry : public AgentRoute { bool force_delete); const MacAddress &mac() const {return mac_;} - const AgentPath *FindMacVmBindingPath() const; + const MacVmBindingPath *FindMacVmBindingPath() const; const AgentPath *FindOvsPath() const; private: diff --git a/src/vnsw/agent/oper/global_vrouter.cc b/src/vnsw/agent/oper/global_vrouter.cc index fc5fabbaaf1..c23c0f7de7b 100644 --- a/src/vnsw/agent/oper/global_vrouter.cc +++ b/src/vnsw/agent/oper/global_vrouter.cc @@ -24,7 +24,7 @@ #include #include -#include +#include #include const std::string GlobalVrouter::kMetadataService = "metadata"; @@ -383,7 +383,8 @@ GlobalVrouter::GlobalVrouter(OperDB *oper) linklocal_route_mgr_(new LinkLocalRouteManager(this)), fabric_dns_resolver_(new FabricDnsResolver(this, *(oper->agent()->event_manager()->io_service()))), - agent_route_encap_update_walker_(new AgentRouteEncap(oper->agent())) { + agent_route_resync_walker_(new AgentRouteResync(oper->agent())), + forwarding_mode_(Agent::L2_L3) { } GlobalVrouter::~GlobalVrouter() { @@ -401,23 +402,32 @@ void GlobalVrouter::CreateDBClients() { void GlobalVrouter::GlobalVrouterConfig(IFMapNode *node) { Agent::VxLanNetworkIdentifierMode cfg_vxlan_network_identifier_mode = Agent::AUTOMATIC; - bool encap_changed = false; + bool resync_vm_interface = false; + bool resync_route = false; if (node->IsDeleted() == false) { autogen::GlobalVrouterConfig *cfg = static_cast(node->GetObject()); - encap_changed = TunnelType::EncapPrioritySync(cfg->encapsulation_priorities()); + resync_route = + TunnelType::EncapPrioritySync(cfg->encapsulation_priorities()); if (cfg->vxlan_network_identifier_mode() == "configured") { cfg_vxlan_network_identifier_mode = Agent::CONFIGURED; } UpdateLinkLocalServiceConfig(cfg->linklocal_services()); + + //Take the forwarding mode if its set, else fallback to l2_l3. + Agent::ForwardingMode new_forwarding_mode = + oper_->agent()->TranslateForwardingMode(cfg->forwarding_mode()); + if (new_forwarding_mode != forwarding_mode_) { + forwarding_mode_ = new_forwarding_mode; + resync_route = true; + resync_vm_interface = true; + } } else { DeleteLinkLocalServiceConfig(); TunnelType::DeletePriorityList(); - encap_changed = true; + resync_route= true; } - bool resync_vm_interface = false; - if (cfg_vxlan_network_identifier_mode != oper_->agent()->vxlan_network_identifier_mode()) { oper_->agent()-> @@ -425,18 +435,19 @@ void GlobalVrouter::GlobalVrouterConfig(IFMapNode *node) { resync_vm_interface = true; } - if (encap_changed) { - AGENT_LOG(GlobalVrouterLog, "Rebake all routes for changed encap"); + //Rebakes + if (resync_route) { + AGENT_LOG(GlobalVrouterLog, "Rebake all routes"); //Resync vm_interfaces to handle ethernet tag change if vxlan changed to //mpls or vice versa. //Update all routes irrespectively as this will handle change of //priority between MPLS-UDP to MPLS-GRE and vice versa. - agent_route_encap_update_walker_.get()->Update(); + agent_route_resync_walker_.get()->Update(); resync_vm_interface = true; } if (resync_vm_interface) { - oper_->agent()->vn_table()->UpdateVxLanNetworkIdentifierMode(); + oper_->agent()->vn_table()->GlobalVrouterConfigChanged(); } } diff --git a/src/vnsw/agent/oper/global_vrouter.h b/src/vnsw/agent/oper/global_vrouter.h index 018ac17a51d..61db618773e 100644 --- a/src/vnsw/agent/oper/global_vrouter.h +++ b/src/vnsw/agent/oper/global_vrouter.h @@ -11,7 +11,7 @@ class OperDB; class VnEntry; class VrfEntry; class IFMapNode; -class AgentRouteEncap; +class AgentRouteResync; namespace autogen { struct LinklocalServiceEntryType; @@ -84,6 +84,7 @@ class GlobalVrouter { void LinkLocalRouteUpdate(const std::vector &addr_list); bool IsAddressInUse(const Ip4Address &ip) const; bool IsLinkLocalAddressInUse(const Ip4Address &ip) const; + Agent::ForwardingMode forwarding_mode() const {return forwarding_mode_;} uint64_t PendingFabricDnsRequests() const; @@ -105,7 +106,8 @@ class GlobalVrouter { LinkLocalServicesMap linklocal_services_map_; boost::scoped_ptr linklocal_route_mgr_; boost::scoped_ptr fabric_dns_resolver_; - boost::scoped_ptr agent_route_encap_update_walker_; + boost::scoped_ptr agent_route_resync_walker_; + Agent::ForwardingMode forwarding_mode_; }; #endif // vnsw_agent_global_router_h_ diff --git a/src/vnsw/agent/oper/interface.cc b/src/vnsw/agent/oper/interface.cc index 57ed934c495..838dacee60a 100644 --- a/src/vnsw/agent/oper/interface.cc +++ b/src/vnsw/agent/oper/interface.cc @@ -288,26 +288,21 @@ bool InterfaceTable::L2VmInterfaceWalk(DBTablePartBase *partition, return true; VmInterface *vm_intf = static_cast(entry); - //In case VN passed is null it is tunnel mode change, - //else its vxlan id change for a VN. - if (!vm_intf->l2_active()) + const VnEntry *vn = vm_intf->vn(); + if (!vm_intf->IsActive()) return true; - if (vm_intf->bridging()) { - bool force_update = false; - if (vm_intf->vxlan_id() != vm_intf->vn()->GetVxLanId()) { - force_update = true; - } - vm_intf->UpdateL2(force_update); - } - return true; + VmInterfaceGlobalVrouterData data(vn->bridging(), + vn->layer3_forwarding(), + vn->GetVxLanId()); + return vm_intf->Resync(this, &data); } void InterfaceTable::VmInterfaceWalkDone(DBTableBase *partition) { walkid_ = DBTableWalker::kInvalidWalkerId; } -void InterfaceTable::UpdateVxLanNetworkIdentifierMode() { +void InterfaceTable::GlobalVrouterConfigChanged() { DBTableWalker *walker = agent_->db()->GetWalker(); if (walkid_ != DBTableWalker::kInvalidWalkerId) { walker->WalkCancel(walkid_); diff --git a/src/vnsw/agent/oper/interface.h b/src/vnsw/agent/oper/interface.h index 4bdd69f8115..ec67d647f18 100644 --- a/src/vnsw/agent/oper/interface.h +++ b/src/vnsw/agent/oper/interface.h @@ -323,7 +323,7 @@ class InterfaceTable : public AgentOperDBTable { bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u); // Handle change in VxLan Identifier mode from global-config - void UpdateVxLanNetworkIdentifierMode(); + void GlobalVrouterConfigChanged(); // Helper functions VrfEntry *FindVrfRef(const std::string &name) const; diff --git a/src/vnsw/agent/oper/multicast.cc b/src/vnsw/agent/oper/multicast.cc index d98db1b8ea5..55d5dc0ffae 100644 --- a/src/vnsw/agent/oper/multicast.cc +++ b/src/vnsw/agent/oper/multicast.cc @@ -120,21 +120,22 @@ void MulticastHandler::HandleVxLanChange(const VnEntry *vn) { } } -void MulticastHandler::HandleTsnSubscription(DBTablePartBase *partition, +void MulticastHandler::HandleVnParametersChange(DBTablePartBase *partition, DBEntryBase *e) { - if (agent_->tsn_enabled() == false) - return; - VnEntry *vn = static_cast(e); + bool deleted = false; + + //Extract paramters from VN. const VrfEntry *vrf = vn->GetVrf(); uint32_t vn_vxlan_id = vn->GetVxLanId(); - bool deleted = false; MulticastDBState *state = static_cast (vn->GetState(partition->parent(), vn_listener_id_)); deleted = vn->IsDeleted() || !(vrf); + //Extract old parameters from state uint32_t old_vxlan_id = state ? state->vxlan_id_ : 0; + boost::system::error_code ec; Ip4Address broadcast = IpAddress::from_string("255.255.255.255", ec).to_v4(); @@ -195,44 +196,13 @@ void MulticastHandler::HandleTsnSubscription(DBTablePartBase *partition, } } -void MulticastHandler::HandleFamilyConfig(const VnEntry *vn) -{ - bool new_bridging = vn->bridging(); - - if (!vn->GetVrf()) - return; - - std::string vrf_name = vn->GetVrf()->GetName(); - for (std::set::iterator it = - GetMulticastObjList().begin(); it != GetMulticastObjList().end(); - it++) { - if (vrf_name != (*it)->vrf_name()) - continue; - - //L2 family disabled - if (!(new_bridging) && (*it)->bridging()) { - (*it)->SetBridging(new_bridging); - if (IS_BCAST_MCAST((*it)->GetGroupAddress())) { - BridgeAgentRouteTable::DeleteBroadcastReq(agent_-> - local_vm_peer(), - (*it)->vrf_name(), 0, - Composite::L2COMP); - } - } - } -} - /* Regsitered call for VN */ void MulticastHandler::ModifyVN(DBTablePartBase *partition, DBEntryBase *e) { const VnEntry *vn = static_cast(e); HandleIpam(vn); - HandleFamilyConfig(vn); - if (agent_->tsn_enabled() == false) - HandleVxLanChange(vn); - if (agent_->tsn_enabled() == true) - HandleTsnSubscription(partition, e); + HandleVnParametersChange(partition, e); } bool MulticastGroupObject::CanBeDeleted() const { @@ -248,6 +218,7 @@ MulticastGroupObject *MulticastHandler::CreateMulticastGroupObject new MulticastGroupObject(vrf_name, ip_addr, vn_name); obj->set_vxlan_id(vxlan_id); AddToMulticastObjList(obj); + obj->CreateEvpnMplsLabel(agent_); return obj; } @@ -302,7 +273,9 @@ void MulticastHandler::ModifyVmInterface(DBTablePartBase *partition, return; } - if (intf->IsDeleted() || (intf->l2_active() == false)) { + if (intf->IsDeleted() || ((vm_itf->l2_active() == false) && + (vm_itf->ipv4_active() == false) && + (vm_itf->ipv6_active() == false))) { DeleteVmInterface(intf); return; } @@ -441,10 +414,6 @@ MulticastHandler::GetInterfaceComponentNHKeyList(MulticastGroupObject *obj, void MulticastHandler::TriggerLocalRouteChange(MulticastGroupObject *obj, const Peer *peer) { - if (obj->bridging() == false) { - return; - } - DBRequest req; ComponentNHKeyList component_nh_key_list; @@ -615,20 +584,15 @@ void MulticastHandler::AddVmInterfaceInFloodGroup(const VmInterface *vm_itf) { //Modify Nexthops if (all_broadcast->AddLocalMember(intf_uuid) == true) { - if (vn->bridging()) { - TriggerLocalRouteChange(all_broadcast, agent_->local_vm_peer()); - } + TriggerLocalRouteChange(all_broadcast, agent_->local_vm_peer()); AddVmToMulticastObjMap(intf_uuid, all_broadcast); } //Modify routes - if ((add_route || (all_broadcast->bridging() != - vn->bridging())) && vn->bridging()) { + if (add_route) { if (TunnelType::ComputeType(TunnelType::AllType()) == TunnelType::VXLAN) { all_broadcast->set_vxlan_id(vn->GetVxLanId()); } - all_broadcast->SetBridging(vn->bridging()); - all_broadcast->CreateEvpnMplsLabel(agent_); TriggerLocalRouteChange(all_broadcast, agent_->local_vm_peer()); } } diff --git a/src/vnsw/agent/oper/multicast.h b/src/vnsw/agent/oper/multicast.h index c8dc26ceefd..18927e20391 100644 --- a/src/vnsw/agent/oper/multicast.h +++ b/src/vnsw/agent/oper/multicast.h @@ -55,8 +55,8 @@ class MulticastGroupObject { const Ip4Address &grp_addr, const std::string &vn_name) : vrf_name_(vrf_name), grp_address_(grp_addr), vn_name_(vn_name), - evpn_mpls_label_(0), vxlan_id_(0), bridging_(true), - peer_identifier_(0), deleted_(false) { + evpn_mpls_label_(0), vxlan_id_(0), peer_identifier_(0), + deleted_(false) { boost::system::error_code ec; src_address_ = IpAddress::from_string("0.0.0.0", ec).to_v4(); local_olist_.clear(); @@ -65,8 +65,8 @@ class MulticastGroupObject { const Ip4Address &grp_addr, const Ip4Address &src_addr) : vrf_name_(vrf_name), grp_address_(grp_addr), src_address_(src_addr), - evpn_mpls_label_(0), vxlan_id_(0), bridging_(true), - peer_identifier_(0), deleted_(false) { + evpn_mpls_label_(0), vxlan_id_(0), peer_identifier_(0), + deleted_(false) { local_olist_.clear(); }; virtual ~MulticastGroupObject() { }; @@ -111,9 +111,7 @@ class MulticastGroupObject { const std::string &GetVnName() { return vn_name_; }; bool IsDeleted() { return deleted_; }; void Deleted(bool val) { deleted_ = val; }; - bool bridging() const {return bridging_;}; - void SetBridging(bool enable) {bridging_ = enable;}; - bool CanUnsubscribe() const {return (deleted_ || !bridging_);} + bool CanUnsubscribe() const {return (deleted_);} void set_vxlan_id(uint32_t vxlan_id) {vxlan_id_ = vxlan_id;} uint32_t vxlan_id() const {return vxlan_id_;} void set_peer_identifier(uint64_t peer_id) {peer_identifier_ = peer_id;} @@ -128,7 +126,6 @@ class MulticastGroupObject { Ip4Address src_address_; uint32_t evpn_mpls_label_; uint32_t vxlan_id_; - bool bridging_; uint64_t peer_identifier_; bool deleted_; std::list local_olist_; /* UUID of local i/f */ @@ -195,10 +192,9 @@ class MulticastHandler { bool fabric, uint32_t ethernet_tag); void HandleIpam(const VnEntry *vn); - void HandleFamilyConfig(const VnEntry *vn); void HandleVxLanChange(const VnEntry *vn); - void HandleTsnSubscription(DBTablePartBase *partition, - DBEntryBase *e); + void HandleVnParametersChange(DBTablePartBase *partition, + DBEntryBase *e); //For test routines to clear all routes and mpls label void Shutdown(); //Multicast obj list addition deletion diff --git a/src/vnsw/agent/oper/operdb_init.cc b/src/vnsw/agent/oper/operdb_init.cc index 2235b570739..3fc2081ead4 100644 --- a/src/vnsw/agent/oper/operdb_init.cc +++ b/src/vnsw/agent/oper/operdb_init.cc @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/src/vnsw/agent/oper/test/test_intf.cc b/src/vnsw/agent/oper/test/test_intf.cc index a04f409ffe9..432857ca458 100644 --- a/src/vnsw/agent/oper/test/test_intf.cc +++ b/src/vnsw/agent/oper/test/test_intf.cc @@ -2802,7 +2802,7 @@ TEST_F(IntfTest, Layer2Mode_2) { client->WaitForIdle(); EXPECT_TRUE(vm_intf->policy_enabled() == false); EXPECT_TRUE(vm_intf->IsL2Active() == true); - EXPECT_TRUE(vm_intf->dhcp_enable_config() == false); + EXPECT_TRUE(vm_intf->dhcp_enable_config() == true); evpn_rt = EvpnRouteGet("vrf1", mac, zero_ip, vm_intf->ethernet_tag()); diff --git a/src/vnsw/agent/oper/vm_interface.cc b/src/vnsw/agent/oper/vm_interface.cc index 74dc2a98a5c..646d7286662 100644 --- a/src/vnsw/agent/oper/vm_interface.cc +++ b/src/vnsw/agent/oper/vm_interface.cc @@ -1054,9 +1054,7 @@ bool VmInterface::Resync(const InterfaceTable *table, Ip4Address old_addr = ip_addr_; Ip6Address old_v6_addr = ip6_addr_; bool old_need_linklocal_ip = need_linklocal_ip_; - bool sg_changed = false; - bool ecmp_changed = false; - bool local_pref_changed = false; + bool force_update = false; Ip4Address old_subnet = subnet_; uint8_t old_subnet_plen = subnet_plen_; int old_ethernet_tag = ethernet_tag_; @@ -1064,8 +1062,7 @@ bool VmInterface::Resync(const InterfaceTable *table, bool old_layer3_forwarding = layer3_forwarding_; if (data) { - ret = data->OnResync(table, this, &sg_changed, &ecmp_changed, - &local_pref_changed); + ret = data->OnResync(table, this, &force_update); } ipv4_active_ = IsIpv4Active(); @@ -1095,10 +1092,9 @@ bool VmInterface::Resync(const InterfaceTable *table, // Apply config based on old and new values ApplyConfig(old_ipv4_active, old_l2_active, old_policy, old_vrf.get(), - old_addr, old_ethernet_tag, old_need_linklocal_ip, sg_changed, - old_ipv6_active, old_v6_addr, ecmp_changed, - local_pref_changed, old_subnet, old_subnet_plen, - old_dhcp_enable, old_layer3_forwarding); + old_addr, old_ethernet_tag, old_need_linklocal_ip, + old_ipv6_active, old_v6_addr, old_subnet, old_subnet_plen, + old_dhcp_enable, old_layer3_forwarding, force_update); return ret; } @@ -1279,6 +1275,15 @@ void VmInterface::ApplyConfigCommon(const VrfEntry *old_vrf, void VmInterface::ApplyMacVmBindingConfig(const VrfEntry *old_vrf, bool old_l2_active, bool old_dhcp_enable) { + //Update DHCP and DNS flag in Interface Class. + if (dhcp_enable_) { + dhcp_enabled_ = true; + dns_enabled_ = true; + } else { + dhcp_enabled_ = false; + dns_enabled_ = false; + } + if (L2Deactivated(old_l2_active)) { DeleteMacVmBinding(old_vrf); return; @@ -1296,13 +1301,13 @@ void VmInterface::ApplyMacVmBindingConfig(const VrfEntry *old_vrf, void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old_policy, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_ethernet_tag, bool old_need_linklocal_ip, - bool sg_changed, bool old_ipv6_active, - const Ip6Address &old_v6_addr, bool ecmp_mode_changed, - bool local_pref_changed, + bool old_ipv6_active, + const Ip6Address &old_v6_addr, const Ip4Address &old_subnet, uint8_t old_subnet_plen, bool old_dhcp_enable, - bool old_layer3_forwarding) { + bool old_layer3_forwarding, + bool force_update) { ApplyConfigCommon(old_vrf, old_l2_active, old_dhcp_enable); //Need not apply config for TOR VMI as it is more of an inidicative //interface. No route addition or NH addition happens for this interface. @@ -1314,11 +1319,6 @@ void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old return; } - bool force_update = false; - if (sg_changed || ecmp_mode_changed | local_pref_changed) { - force_update = true; - } - bool policy_change = (policy_enabled_ != old_policy); if (ipv4_active_ == true || l2_active_ == true) { @@ -1331,14 +1331,6 @@ void VmInterface::ApplyConfig(bool old_ipv4_active, bool old_l2_active, bool old vrf_->CreateTableLabel(); } - //Irrespective of interface state, if ipv4 forwarding mode is enabled - //enable L3 services on this interface - if (layer3_forwarding_) { - UpdateL3Services(dhcp_enable_, true); - } else { - UpdateL3Services(false, false); - } - // Add/Del/Update L3 if ((ipv4_active_ || ipv6_active_) && layer3_forwarding_) { UpdateL3(old_ipv4_active, old_vrf, old_addr, old_ethernet_tag, force_update, @@ -1464,11 +1456,19 @@ bool VmInterfaceConfigData::OnDelete(const InterfaceTable *table, } bool VmInterfaceConfigData::OnResync(const InterfaceTable *table, - VmInterface *vmi, bool *sg_changed, - bool *ecmp_changed, - bool *local_pref_changed) const { - return vmi->CopyConfig(table, this, sg_changed, ecmp_changed, - local_pref_changed); + VmInterface *vmi, + bool *force_update) const { + bool sg_changed = false; + bool ecmp_changed = false; + bool local_pref_changed = false; + bool ret = false; + + ret = vmi->CopyConfig(table, this, &sg_changed, &ecmp_changed, + &local_pref_changed); + if (sg_changed || ecmp_changed || local_pref_changed) + *force_update = true; + + return ret; } // Copies configuration from DB-Request data. The actual applying of @@ -1524,6 +1524,12 @@ bool VmInterface::CopyConfig(const InterfaceTable *table, ret = true; } + bool bridging_val = vn ? vn->bridging() : false; + if (bridging_ != bridging_val) { + bridging_ = bridging_val; + ret = true; + } + int vxlan_id = vn ? vn->GetVxLanId() : 0; if (vxlan_id_ != vxlan_id) { vxlan_id_ = vxlan_id; @@ -1544,20 +1550,18 @@ bool VmInterface::CopyConfig(const InterfaceTable *table, ret = true; } - bool val = layer3_forwarding_ ? data->need_linklocal_ip_ : false; - if (need_linklocal_ip_ != val) { - need_linklocal_ip_ = val; + if (need_linklocal_ip_ != data->need_linklocal_ip_) { + need_linklocal_ip_ = data->need_linklocal_ip_; ret = true; } // CopyIpAddress uses fabric_port_. So, set it before CopyIpAddresss - val = layer3_forwarding_ ? data->fabric_port_ : false; - if (fabric_port_ != val) { - fabric_port_ = val; + if (fabric_port_ != data->fabric_port_) { + fabric_port_ = data->fabric_port_; ret = true; } - Ip4Address ipaddr = layer3_forwarding_ ? data->addr_ : Ip4Address(0); + Ip4Address ipaddr = data->addr_; if (CopyIpAddress(ipaddr)) { ret = true; } @@ -1565,9 +1569,8 @@ bool VmInterface::CopyConfig(const InterfaceTable *table, ret = true; } - bool dhcp_enable = layer3_forwarding_ ? data->dhcp_enable_: false; - if (dhcp_enable_ != dhcp_enable) { - dhcp_enable_ = dhcp_enable; + if (dhcp_enable_ != data->dhcp_enable_) { + dhcp_enable_ = data->dhcp_enable_; ret = true; } @@ -1788,9 +1791,8 @@ bool VmInterfaceNovaData::OnDelete(const InterfaceTable *table, } bool VmInterfaceNovaData::OnResync(const InterfaceTable *table, - VmInterface *vmi, bool *sg_changed, - bool *ecmp_changed, - bool *local_pref_changed) const { + VmInterface *vmi, + bool *force_update) const { bool ret = false; if (vmi->vm_project_uuid_ != vm_project_uuid_) { @@ -1816,9 +1818,8 @@ bool VmInterfaceNovaData::OnResync(const InterfaceTable *table, // VmInterfaceMirrorData routines ///////////////////////////////////////////////////////////////////////////// bool VmInterfaceMirrorData::OnResync(const InterfaceTable *table, - VmInterface *vmi, bool *sg_changed, - bool *ecmp_changed, - bool *local_pref_changed) const { + VmInterface *vmi, + bool *force_update) const { bool ret = false; MirrorEntry *mirror_entry = NULL; @@ -1841,9 +1842,8 @@ bool VmInterfaceMirrorData::OnResync(const InterfaceTable *table, // For interfaces in IP Fabric VRF, we send DHCP requests to external servers // if config doesnt provide an address. This address is updated here. bool VmInterfaceIpAddressData::OnResync(const InterfaceTable *table, - VmInterface *vmi, bool *sg_changed, - bool *ecmp_changed, - bool *local_pref_changed) const { + VmInterface *vmi, + bool *force_update) const { bool ret = false; if (vmi->os_index_ == VmInterface::kInvalidIndex) { @@ -1870,9 +1870,8 @@ bool VmInterfaceIpAddressData::OnResync(const InterfaceTable *table, ///////////////////////////////////////////////////////////////////////////// // Resync oper-state for the interface bool VmInterfaceOsOperStateData::OnResync(const InterfaceTable *table, - VmInterface *vmi, bool *sg_changed, - bool *ecmp_changed, - bool *local_pref_changed) const { + VmInterface *vmi, + bool *force_update) const { bool ret = false; uint32_t old_os_index = vmi->os_index_; @@ -1894,6 +1893,28 @@ bool VmInterfaceOsOperStateData::OnResync(const InterfaceTable *table, return ret; } +bool VmInterfaceGlobalVrouterData::OnResync(const InterfaceTable *table, + VmInterface *vmi, + bool *force_update) const { + bool ret = false; + + if (bridging_ != vmi->bridging_) { + vmi->bridging_ = bridging_; + *force_update = true; + ret = true; + } + if (layer3_forwarding_ != vmi->layer3_forwarding_) { + vmi->layer3_forwarding_ = layer3_forwarding_; + *force_update = true; + ret = true; + } + + if (vxlan_id_ != vmi->vxlan_id_) + ret = true; + + return ret; +} + ///////////////////////////////////////////////////////////////////////////// // VM Port Entry utility routines ///////////////////////////////////////////////////////////////////////////// @@ -2967,11 +2988,6 @@ void VmInterface::DeleteRoute(const std::string &vrf_name, return; } -void VmInterface::UpdateL3Services(bool dhcp, bool dns) { - dhcp_enabled_ = dhcp; - dns_enabled_ = dns; -} - // DHCP options applicable to the Interface bool VmInterface::GetInterfaceDhcpOptions( std::vector *options) const { diff --git a/src/vnsw/agent/oper/vm_interface.h b/src/vnsw/agent/oper/vm_interface.h index 579b66fec35..b7eaefd7b9b 100644 --- a/src/vnsw/agent/oper/vm_interface.h +++ b/src/vnsw/agent/oper/vm_interface.h @@ -498,6 +498,7 @@ class VmInterface : public Interface { const MacAddress &mac) const; uint32_t ethernet_tag() const {return ethernet_tag_;} void UpdateVxLan(); + bool IsActive() const; Agent *agent() const { return (static_cast(get_table()))->agent(); } @@ -508,12 +509,11 @@ class VmInterface : public Interface { friend struct VmInterfaceIpAddressData; friend struct VmInterfaceOsOperStateData; friend struct VmInterfaceMirrorData; + friend struct VmInterfaceGlobalVrouterData; - bool IsActive() const; bool IsIpv4Active() const; bool IsL3Active() const; bool PolicyEnabled() const; - void UpdateL3Services(bool dhcp, bool dns); void AddRoute(const std::string &vrf_name, const IpAddress &ip, uint32_t plen, const std::string &vn_name, bool policy, bool ecmp, const IpAddress &gw_ip); @@ -547,11 +547,10 @@ class VmInterface : public Interface { void ApplyConfig(bool old_ipv4_active,bool old_l2_active, bool old_policy, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_ethernet_tag, bool old_need_linklocal_ip, - bool sg_changed, bool old_ipv6_active, - const Ip6Address &old_v6_addr, bool ecmp_changed, - bool local_pref_changed, const Ip4Address &old_subnet, - const uint8_t old_subnet_plen, bool old_dhcp_enable, - bool old_layer3_forwarding); + bool old_ipv6_active, const Ip6Address &old_v6_addr, + const Ip4Address &old_subnet, const uint8_t old_subnet_plen, + bool old_dhcp_enable, bool old_layer3_forwarding, + bool force_update); void UpdateL3(bool old_ipv4_active, VrfEntry *old_vrf, const Ip4Address &old_addr, int old_ethernet_tag, bool force_update, bool policy_change, bool old_ipv6_active, @@ -732,7 +731,8 @@ struct VmInterfaceData : public InterfaceData { INSTANCE_MSG, MIRROR, IP_ADDR, - OS_OPER_STATE + OS_OPER_STATE, + GLOBAL_VROUTER }; VmInterfaceData(Agent *agent, IFMapNode *node, Type type, @@ -751,8 +751,7 @@ struct VmInterfaceData : public InterfaceData { return true; } virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const = 0; + bool *force_update) const = 0; Type type_; }; @@ -764,8 +763,7 @@ struct VmInterfaceIpAddressData : public VmInterfaceData { Interface::TRANSPORT_INVALID) { } virtual ~VmInterfaceIpAddressData() { } virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const; + bool *force_update) const; }; // Structure used when type=OS_OPER_STATE Used to update interface os oper-state @@ -776,8 +774,7 @@ struct VmInterfaceOsOperStateData : public VmInterfaceData { Interface::TRANSPORT_INVALID) { } virtual ~VmInterfaceOsOperStateData() { } virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const; + bool *force_update) const; }; // Structure used when type=MIRROR. Used to update IP-Address of VM-Interface @@ -789,8 +786,7 @@ struct VmInterfaceMirrorData : public VmInterfaceData { } virtual ~VmInterfaceMirrorData() { } virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const; + bool *force_update) const; bool mirror_enable_; std::string analyzer_name_; @@ -805,8 +801,7 @@ struct VmInterfaceConfigData : public VmInterfaceData { virtual bool OnDelete(const InterfaceTable *table, VmInterface *entry) const; virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const; + bool *force_update) const; Ip4Address addr_; Ip6Address ip6_addr_; @@ -872,8 +867,7 @@ struct VmInterfaceNovaData : public VmInterfaceData { virtual bool OnDelete(const InterfaceTable *table, VmInterface *entry) const; virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, - bool *sg_changed, bool *ecmp_changed, - bool *local_pref_changed) const; + bool *force_update) const; Ip4Address ipv4_addr_; Ip6Address ipv6_addr_; @@ -888,4 +882,22 @@ struct VmInterfaceNovaData : public VmInterfaceData { VmInterface::VmiType vmi_type_; }; +struct VmInterfaceGlobalVrouterData : public VmInterfaceData { + VmInterfaceGlobalVrouterData(bool bridging, + bool layer3_forwarding, + int vxlan_id) : + VmInterfaceData(NULL, NULL, GLOBAL_VROUTER, Interface::TRANSPORT_INVALID), + bridging_(bridging), + layer3_forwarding_(layer3_forwarding), + vxlan_id_(vxlan_id) { + } + virtual ~VmInterfaceGlobalVrouterData() { } + virtual bool OnResync(const InterfaceTable *table, VmInterface *vmi, + bool *force_update) const; + + bool bridging_; + bool layer3_forwarding_; + int vxlan_id_; +}; + #endif // vnsw_agent_vm_interface_hpp diff --git a/src/vnsw/agent/oper/vn.cc b/src/vnsw/agent/oper/vn.cc index f1fbcecbf9d..3475450160a 100644 --- a/src/vnsw/agent/oper/vn.cc +++ b/src/vnsw/agent/oper/vn.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "net/address_util.h" @@ -90,7 +91,7 @@ VnEntry::VnEntry(Agent *agent, uuid id) : AgentOperDBEntry(), agent_(agent), uuid_(id), vxlan_id_(0), vnid_(0), bridging_(true), layer3_forwarding_(true), admin_state_(true), table_label_(0), enable_rpf_(true), flood_unknown_unicast_(false), - old_vxlan_id_(0) { + old_vxlan_id_(0), forwarding_mode_(Agent::L2_L3) { } VnEntry::~VnEntry() { @@ -221,7 +222,51 @@ int VnEntry::ComputeEthernetTag() const { bool VnEntry::Resync() { VnTable *table = static_cast(get_table()); - return table->RebakeVxlan(this, false); + bool ret = false; + + //Evaluate rebake of vxlan + ret |= table->RebakeVxlan(this, false); + //Evaluate forwarding mode change + ret |= table->EvaluateForwardingMode(this); + + return ret; +} + +bool VnTable::GetLayer3ForwardingConfig +(Agent::ForwardingMode forwarding_mode) const { + if (forwarding_mode == Agent::L2) { + return false; + } + return true; +} + +bool VnTable::GetBridgingConfig(Agent::ForwardingMode forwarding_mode) const { + if (forwarding_mode == Agent::L3) { + return false; + } + return true; +} + +bool VnTable::EvaluateForwardingMode(VnEntry *vn) { + bool ret = false; + Agent::ForwardingMode forwarding_mode = vn->forwarding_mode(); + //Evaluate only if VN does not have specific forwarding mode change. + if (forwarding_mode == Agent::NONE) { + Agent::ForwardingMode global_forwarding_mode = + agent()->oper_db()->global_vrouter()->forwarding_mode(); + bool layer3_forwarding = + GetLayer3ForwardingConfig(global_forwarding_mode); + if (layer3_forwarding != vn->layer3_forwarding()) { + vn->set_layer3_forwarding(layer3_forwarding); + ret |= true; + } + bool bridging = GetBridgingConfig(global_forwarding_mode); + if (bridging != vn->bridging()) { + vn->set_bridging(bridging); + ret |= true; + } + } + return ret; } // Rebake handles @@ -290,13 +335,12 @@ bool VnTable::VnEntryWalk(DBTablePartBase *partition, DBEntryBase *entry) { void VnTable::VnEntryWalkDone(DBTableBase *partition) { walkid_ = DBTableWalker::kInvalidWalkerId; - agent()->interface_table()-> - UpdateVxLanNetworkIdentifierMode(); + agent()->interface_table()->GlobalVrouterConfigChanged(); agent()->physical_device_vn_table()-> UpdateVxLanNetworkIdentifierMode(); } -void VnTable::UpdateVxLanNetworkIdentifierMode() { +void VnTable::GlobalVrouterConfigChanged() { DBTableWalker *walker = agent()->db()->GetWalker(); if (walkid_ != DBTableWalker::kInvalidWalkerId) { walker->WalkCancel(walkid_); @@ -439,6 +483,11 @@ bool VnTable::ChangeHandler(DBEntry *entry, const DBRequest *req) { ret = true; } + if (vn->forwarding_mode_ != data->forwarding_mode_) { + vn->forwarding_mode_ = data->forwarding_mode_; + ret = true; + } + if (rebake_vxlan) { ret |= RebakeVxlan(vn, false); } @@ -540,23 +589,39 @@ int VnTable::ComputeCfgVxlanId(IFMapNode *node) { } void VnTable::CfgForwardingFlags(IFMapNode *node, bool *l2, bool *l3, - bool *rpf, bool *flood_unknown_unicast) { - *l2 = true; - *l3 = true; + bool *rpf, bool *flood_unknown_unicast, + Agent::ForwardingMode *forwarding_mode) { *rpf = true; VirtualNetwork *cfg = static_cast (node->GetObject()); autogen::VirtualNetworkType properties = cfg->properties(); - if (properties.forwarding_mode == "l2") { - *l3 = false; - } if (properties.rpf == "disable") { *rpf = false; } *flood_unknown_unicast = cfg->flood_unknown_unicast(); -} + + //dervived forwarding mode is resultant of configured VN forwarding and global + //configure forwarding mode. It is then used to setup the VN forwarding + //mode. + //In derivation, global configured forwarding mode is consulted only if VN + //configured f/wing mode is not set. + *forwarding_mode = + agent()->TranslateForwardingMode(properties.forwarding_mode); + Agent::ForwardingMode derived_forwarding_mode = *forwarding_mode; + if (derived_forwarding_mode == Agent::NONE) { + //Use global configured forwarding mode. + derived_forwarding_mode = agent()->oper_db()->global_vrouter()-> + forwarding_mode(); + } + + //Set the forwarding mode in VN based on calculation above. + //By default assume both bridging and layer3_forwarding is enabled. + //Flap the mode if configured forwarding mode is not "l2_l3" i.e. l2 or l3. + *l2 = GetBridgingConfig(derived_forwarding_mode); + *l3 = GetLayer3ForwardingConfig(derived_forwarding_mode); + } VnData *VnTable::BuildData(IFMapNode *node) { VirtualNetwork *cfg = static_cast (node->GetObject()); @@ -646,14 +711,15 @@ VnData *VnTable::BuildData(IFMapNode *node) { bool layer3_forwarding; bool enable_rpf; bool flood_unknown_unicast; + Agent::ForwardingMode forwarding_mode; CfgForwardingFlags(node, &bridging, &layer3_forwarding, &enable_rpf, - &flood_unknown_unicast); + &flood_unknown_unicast, &forwarding_mode); return new VnData(agent(), node, node->name(), acl_uuid, vrf_name, mirror_acl_uuid, mirror_cfg_acl_uuid, vn_ipam, vn_ipam_data, cfg->properties().vxlan_network_identifier, GetCfgVnId(cfg), bridging, layer3_forwarding, cfg->id_perms().enable, enable_rpf, - flood_unknown_unicast); + flood_unknown_unicast, forwarding_mode); } bool VnTable::IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u) { @@ -714,7 +780,7 @@ void VnTable::AddVn(const uuid &vn_uuid, const string &name, nil_uuid(), ipam, vn_ipam_data, vn_id, vxlan_id, true, true, admin_state, enable_rpf, - flood_unknown_unicast); + flood_unknown_unicast, Agent::NONE); req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; req.key.reset(key); diff --git a/src/vnsw/agent/oper/vn.h b/src/vnsw/agent/oper/vn.h index 2d32ca1bb26..d56e7aae77d 100644 --- a/src/vnsw/agent/oper/vn.h +++ b/src/vnsw/agent/oper/vn.h @@ -89,14 +89,15 @@ struct VnData : public AgentOperDBData { const std::vector &ipam, const VnIpamDataMap &vn_ipam_data, int vxlan_id, int vnid, bool bridging, bool layer3_forwarding, bool admin_state, bool enable_rpf, - bool flood_unknown_unicast) : + bool flood_unknown_unicast, Agent::ForwardingMode forwarding_mode) : AgentOperDBData(agent, node), name_(name), vrf_name_(vrf_name), acl_id_(acl_id), mirror_acl_id_(mirror_acl_id), mirror_cfg_acl_id_(mc_acl_id), ipam_(ipam), vn_ipam_data_(vn_ipam_data), vxlan_id_(vxlan_id), vnid_(vnid), bridging_(bridging), layer3_forwarding_(layer3_forwarding), admin_state_(admin_state), enable_rpf_(enable_rpf), - flood_unknown_unicast_(flood_unknown_unicast) { + flood_unknown_unicast_(flood_unknown_unicast), + forwarding_mode_(forwarding_mode) { }; virtual ~VnData() { } @@ -114,6 +115,7 @@ struct VnData : public AgentOperDBData { bool admin_state_; bool enable_rpf_; bool flood_unknown_unicast_; + Agent::ForwardingMode forwarding_mode_; }; class VnEntry : AgentRefCount, public AgentOperDBEntry { @@ -156,8 +158,13 @@ class VnEntry : AgentRefCount, public AgentOperDBEntry { const VxLanId *vxlan_id_ref() const {return vxlan_id_ref_.get();} const VxLanId *vxlan_id() const {return vxlan_id_ref_.get();} + void set_bridging(bool bridging) {bridging_ = bridging;} bool bridging() const {return bridging_;}; bool layer3_forwarding() const {return layer3_forwarding_;}; + void set_layer3_forwarding(bool layer3_forwarding) + {layer3_forwarding_ = layer3_forwarding;} + Agent::ForwardingMode forwarding_mode() const {return forwarding_mode_;} + bool admin_state() const {return admin_state_;} bool enable_rpf() const {return enable_rpf_;} bool flood_unknown_unicast() const {return flood_unknown_unicast_;} @@ -192,6 +199,7 @@ class VnEntry : AgentRefCount, public AgentOperDBEntry { bool enable_rpf_; bool flood_unknown_unicast_; uint32_t old_vxlan_id_; + Agent::ForwardingMode forwarding_mode_; DISALLOW_COPY_AND_ASSIGN(VnEntry); }; @@ -218,7 +226,8 @@ class VnTable : public AgentOperDBTable { int ComputeCfgVxlanId(IFMapNode *node); void CfgForwardingFlags(IFMapNode *node, bool *l2, bool *l3, bool *rpf, - bool *flood_unknown_unicast); + bool *flood_unknown_unicast, + Agent::ForwardingMode *forwarding_mode); static DBTableBase *CreateTable(DB *db, const std::string &name); @@ -232,10 +241,13 @@ class VnTable : public AgentOperDBTable { void DelVn(const uuid &vn_uuid); void ResyncVxlan(const boost::uuids::uuid &vn); VnEntry *Find(const uuid &vn_uuid); - void UpdateVxLanNetworkIdentifierMode(); + void GlobalVrouterConfigChanged(); bool VnEntryWalk(DBTablePartBase *partition, DBEntryBase *entry); void VnEntryWalkDone(DBTableBase *partition); bool RebakeVxlan(VnEntry *vn, bool op_del); + bool EvaluateForwardingMode(VnEntry *vn); + bool GetLayer3ForwardingConfig(Agent::ForwardingMode forwarding_mode) const; + bool GetBridgingConfig(Agent::ForwardingMode forwarding_mode) const; private: static VnTable *vn_table_; diff --git a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/test_ovs_multicast_local.cc b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/test_ovs_multicast_local.cc index 0a4f52dd283..a2fd193d9da 100644 --- a/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/test_ovs_multicast_local.cc +++ b/src/vnsw/agent/ovs_tor_agent/ovsdb_client/test/test_ovs_multicast_local.cc @@ -288,9 +288,9 @@ TEST_F(OvsBaseTest, tunnel_nh_ovs_multicast) { client->WaitForIdle(); BridgeRouteEntry *rt = L2RouteGet("vrf1", mac); - const AgentPath *path = rt->GetActivePath(); + const AgentPath *path = rt->FindPath(peer); EXPECT_TRUE(path->tunnel_dest() == tor_ip); - const TunnelNH *nh = dynamic_cast(rt->GetActiveNextHop()); + const TunnelNH *nh = dynamic_cast(path->nexthop()); EXPECT_TRUE(nh != NULL); EXPECT_TRUE(*nh->GetDip() == tor_ip); EXPECT_TRUE(*nh->GetSip() == tsn_ip); @@ -300,9 +300,9 @@ TEST_F(OvsBaseTest, tunnel_nh_ovs_multicast) { WAIT_FOR(1000, 100, (L2RouteGet("vrf1", mac) != NULL)); rt = L2RouteGet("vrf1", mac); - path = rt->GetActivePath(); + path = rt->FindPath(peer); EXPECT_TRUE(path->tunnel_dest() == tor_ip); - nh = dynamic_cast(rt->GetActiveNextHop()); + nh = dynamic_cast(path->nexthop()); EXPECT_TRUE(nh != NULL); EXPECT_TRUE(*nh->GetDip() == tor_ip); EXPECT_TRUE(*nh->GetSip() == tsn_ip); diff --git a/src/vnsw/agent/pkt/test/egress-flow.xml b/src/vnsw/agent/pkt/test/egress-flow.xml index 678320381e7..34b32fed9f8 100644 --- a/src/vnsw/agent/pkt/test/egress-flow.xml +++ b/src/vnsw/agent/pkt/test/egress-flow.xml @@ -38,10 +38,10 @@ - - @@ -76,10 +76,10 @@ - - diff --git a/src/vnsw/agent/pkt/test/l2-sg-flow.xml b/src/vnsw/agent/pkt/test/l2-sg-flow.xml index 44da3f117b5..060a960fcc7 100644 --- a/src/vnsw/agent/pkt/test/l2-sg-flow.xml +++ b/src/vnsw/agent/pkt/test/l2-sg-flow.xml @@ -58,10 +58,10 @@ - - @@ -73,10 +73,10 @@ - - @@ -93,10 +93,10 @@ - - diff --git a/src/vnsw/agent/pkt/test/test_xml_packet_ut.cc b/src/vnsw/agent/pkt/test/test_xml_packet_ut.cc index 3e212e72faf..0831db0c052 100644 --- a/src/vnsw/agent/pkt/test/test_xml_packet_ut.cc +++ b/src/vnsw/agent/pkt/test/test_xml_packet_ut.cc @@ -147,9 +147,7 @@ TEST_F(TestPkt, flow_tsn_mode_1) { client->WaitForIdle(); boost::system::error_code ec; - BgpPeer *bgp_peer = CreateBgpPeer(Ip4Address::from_string("0.0.0.1", ec), - "xmpp channel"); - EcmpTunnelRouteAdd(agent, bgp_peer, "vrf1", "1.1.1.0", 24, + EcmpTunnelRouteAdd(agent, bgp_peer_, "vrf1", "1.1.1.0", 24, "100.100.100.1", 1, "100.100.100.2", 2, "vn1"); AgentUtXmlTest test("controller/src/vnsw/agent/pkt/test/tsn-flow.xml"); @@ -164,13 +162,11 @@ TEST_F(TestPkt, flow_tsn_mode_1) { test.Run(); } - DeleteRoute("vrf1", "1.1.1.0", 24, bgp_peer); + DeleteRoute("vrf1", "1.1.1.0", 24, bgp_peer_); client->WaitForIdle(); DelIPAM("vn1"); DelVn("vn1"); client->WaitForIdle(); - DeleteBgpPeer(bgp_peer); - client->WaitForIdle(); } int main(int argc, char *argv[]) { diff --git a/src/vnsw/agent/pkt/test/unknown-unicast-flood.xml b/src/vnsw/agent/pkt/test/unknown-unicast-flood.xml index 4b541ed9abd..dbade153221 100644 --- a/src/vnsw/agent/pkt/test/unknown-unicast-flood.xml +++ b/src/vnsw/agent/pkt/test/unknown-unicast-flood.xml @@ -52,7 +52,7 @@ - @@ -67,7 +67,7 @@ - @@ -78,7 +78,7 @@ flood-unknown-unicast="false"/> - diff --git a/src/vnsw/agent/test/SConscript b/src/vnsw/agent/test/SConscript index b060f806730..5c92db4b6ae 100644 --- a/src/vnsw/agent/test/SConscript +++ b/src/vnsw/agent/test/SConscript @@ -60,6 +60,7 @@ test_vm = AgentEnv.MakeTestCmd(env, 'test_vm', flaky_agent_suite) test_peer_del = AgentEnv.MakeTestCmd(env, 'test_peer_del', flaky_agent_suite) test_vmport_cfg = AgentEnv.MakeTestCmd(env, 'test_vmport_cfg', flaky_agent_suite) test_fip_cfg = AgentEnv.MakeTestCmd(env, 'test_fip_cfg', flaky_agent_suite) +test_forwarding_mode = AgentEnv.MakeTestCmd(env, 'test_forwarding_mode', agent_suite) test_route = AgentEnv.MakeTestCmd(env, 'test_route', flaky_agent_suite) test_l2route = AgentEnv.MakeTestCmd(env, 'test_l2route', flaky_agent_suite) test_cfg = AgentEnv.MakeTestCmd(env, 'test_cfg', flaky_agent_suite) diff --git a/src/vnsw/agent/test/test_cmn_util.h b/src/vnsw/agent/test/test_cmn_util.h index b225fd70d9a..917e17df7d9 100644 --- a/src/vnsw/agent/test/test_cmn_util.h +++ b/src/vnsw/agent/test/test_cmn_util.h @@ -212,7 +212,9 @@ void DelVm(const char *name); void AddVrf(const char *name, int id = 0); void DelVrf(const char *name); void ModifyForwardingModeVn(const string &name, int id, const string &fw_mode); +void AddL2L3Vn(const char *name, int id); void AddL2Vn(const char *name, int id); +void AddL3Vn(const char *name, int id); void AddVn(const char *name, int id, bool admin_state = true); void DelVn(const char *name); void AddPort(const char *name, int id, const char *attr = NULL); @@ -263,6 +265,8 @@ void CreateVmportEnvInternal(struct PortInfo *input, int count, int acl_id = 0, bool with_ip = false, bool ecmp = false, bool vn_admin_state = true, bool with_ip6 = false, bool send_nova_msg = true); +void CreateL3VmportEnv(struct PortInfo *input, int count, int acl_id = 0, + const char *vn = NULL, const char *vrf = NULL); void CreateV6VmportEnv(struct PortInfo *input, int count, int acl_id = 0, const char *vn = NULL, const char *vrf = NULL, bool with_v4_ip = true); @@ -370,6 +374,7 @@ void AddEncapList(Agent *agent, const char *encap1, const char *encap2, void DelEncapList(); void DelEncapList(Agent *agent); void VxLanNetworkIdentifierMode(bool config); +void GlobalForwardingMode(std::string mode); int MplsToVrfId(int label); void AddInterfaceRouteTable(const char *name, int id, TestIp4Prefix *addr, int count); diff --git a/src/vnsw/agent/test/test_forwarding_mode.cc b/src/vnsw/agent/test/test_forwarding_mode.cc new file mode 100644 index 00000000000..21dbff67e80 --- /dev/null +++ b/src/vnsw/agent/test/test_forwarding_mode.cc @@ -0,0 +1,683 @@ +// +// test_forwarding_mode.cc +// vnsw/agent/test +// +// Created by Praveen K V +// Copyright (c) 2015 Contrail Systems. All rights reserved. +// +#include "base/os.h" +#include +#include +#include +#include +#include + +#include + +#include "cfg/cfg_init.h" +#include "cfg/cfg_interface.h" +#include "oper/operdb_init.h" +#include "controller/controller_init.h" +#include "pkt/pkt_init.h" +#include "services/services_init.h" +#include "vrouter/ksync/ksync_init.h" +#include "oper/interface_common.h" +#include "oper/nexthop.h" +#include "oper/tunnel_nh.h" +#include "route/route.h" +#include "oper/vrf.h" +#include "oper/mpls.h" +#include "oper/vm.h" +#include "oper/vn.h" +#include "filter/acl.h" +#include "test_cmn_util.h" +#include "kstate/test/test_kstate_util.h" +#include "vr_types.h" + +#include +#include +using namespace boost::assign; +std::string eth_itf; +bool dhcp_external; + +struct PortInfo input[] = { + {"vnet1", 1, "1.1.1.10", "00:00:01:01:01:10", 1, 1}, +}; + +IpamInfo ipam_info_dhcp_enable[] = { + {"1.1.1.0", 24, "1.1.1.200", true}, +}; + +IpamInfo ipam_info_dhcp_disable[] = { + {"1.1.1.0", 24, "1.1.1.200", false}, +}; + +void RouterIdDepInit(Agent *agent) { +} + +static void ValidateSandeshResponse(Sandesh *sandesh, vector &result) { + //TBD + //Validate the response by the expectation +} + +class ForwardingModeTest : public ::testing::Test { +public: + +protected: + ForwardingModeTest() { + } + + ~ForwardingModeTest() { + } + + virtual void SetUp() { + vrf_name_ = "vrf1"; + eth_name_ = eth_itf; + default_dest_ip_ = Ip4Address::from_string("0.0.0.0"); + agent_ = Agent::GetInstance(); + bgp_peer_ = NULL; + + if (agent_->router_id_configured()) { + vhost_ip_ = agent_->router_id(); + } else { + vhost_ip_ = Ip4Address::from_string("10.1.1.10"); + } + server1_ip_ = Ip4Address::from_string("10.1.1.11"); + + strcpy(local_vm_mac_str_, "00:00:01:01:01:10"); + local_vm_mac_ = MacAddress::FromString(local_vm_mac_str_); + strcpy(local_vm_ip4_str_, "1.1.1.10"); + local_vm_ip4_ = Ip4Address::from_string(local_vm_ip4_str_); + strcpy(local_vm_ip6_str_, "fdff::10"); + local_vm_ip6_ = Ip6Address::from_string(local_vm_ip6_str_); + + strcpy(remote_vm_mac_str_, "00:00:01:01:01:11"); + remote_vm_mac_ = MacAddress::FromString(remote_vm_mac_str_); + strcpy(remote_vm_ip4_str_, "1.1.1.11"); + remote_vm_ip4_ = Ip4Address::from_string(remote_vm_ip4_str_); + strcpy(remote_vm_ip6_str_, "fdff::11"); + remote_vm_ip6_ = Ip6Address::from_string(remote_vm_ip6_str_); + + client->Reset(); + //Create a VRF + VrfAddReq(vrf_name_.c_str()); + PhysicalInterface::CreateReq(agent_->interface_table(), + eth_name_, + agent_->fabric_vrf_name(), + PhysicalInterface::FABRIC, + PhysicalInterface::ETHERNET, false, nil_uuid(), + Ip4Address(0), Interface::TRANSPORT_ETHERNET); + AddResolveRoute(server1_ip_, 24); + client->WaitForIdle(); + bgp_peer_ = CreateBgpPeer("127.0.0.1", "remote"); + client->WaitForIdle(); + } + + virtual void TearDown() { + VrfDelReq(vrf_name_.c_str()); + client->WaitForIdle(); + WAIT_FOR(100, 100, (VrfFind(vrf_name_.c_str()) != true)); + DeleteBgpPeer(bgp_peer_); + client->WaitForIdle(); + } + + void AddRemoteVmRoute(MacAddress &remote_vm_mac, const Ip4Address &ip_addr, + const Ip4Address &server_ip, + uint32_t label, TunnelType::TypeBmap bmap) { + //Use any other peer than localvmpeer + Inet4TunnelRouteAdd(bgp_peer_, vrf_name_, ip_addr, 32, server_ip, + bmap, label+1, vrf_name_, + SecurityGroupList(), PathPreference()); + client->WaitForIdle(); + BridgeTunnelRouteAdd(bgp_peer_, vrf_name_, bmap, server_ip, + label, remote_vm_mac, ip_addr, 32); + client->WaitForIdle(); + } + + void AddResolveRoute(const Ip4Address &server_ip, uint32_t plen) { + InetInterfaceKey vhost_key(agent_->vhost_interface()->name()); + agent_->fabric_inet4_unicast_table()->AddResolveRoute( + agent_->local_peer(), + agent_->fabric_vrf_name(), server_ip, plen, vhost_key, + 0, false, "", SecurityGroupList()); + client->WaitForIdle(); + } + + void DeleteRoute(const Peer *peer, const std::string &vrf_name, + MacAddress &remote_vm_mac, const IpAddress &ip_addr) { + const BgpPeer *bgp_peer = static_cast(peer); + if (bgp_peer) { + EvpnAgentRouteTable::DeleteReq(peer, vrf_name_, remote_vm_mac, + ip_addr, 0, + (new ControllerVmRoute(bgp_peer))); + } else { + EvpnAgentRouteTable::DeleteReq(peer, vrf_name_, remote_vm_mac, + ip_addr, 0, NULL); + } + client->WaitForIdle(); + WAIT_FOR(1000, 1000, (L2RouteFind(vrf_name, remote_vm_mac, ip_addr) == + false)); + agent_->fabric_inet4_unicast_table()->DeleteReq(peer, vrf_name, + ip_addr, 32, NULL); + client->WaitForIdle(); + } + + void VerifyVmInterfaceDhcp() { + //Validate ksync + InterfaceKSyncObject *obj = agent_->ksync()->interface_ksync_obj();; + VmInterface *vm_intf = static_cast(VmPortGet(1)); + std::auto_ptr ksync(new InterfaceKSyncEntry(obj, + vm_intf)); + ksync->Sync(vm_intf); + if (dhcp_external) { + EXPECT_TRUE(ksync->dhcp_enable() == false); + } else { + EXPECT_TRUE(ksync->dhcp_enable() == true); + } + } + + void VerifyL2L3Mode() { + //First verify multicast + MulticastGroupObject *obj = + MulticastHandler::GetInstance()->FindFloodGroupObject("vrf1"); + EXPECT_TRUE(obj != NULL); + BridgeRouteEntry *mc_route = + L2RouteGet(vrf_name_, MacAddress::FromString("ff:ff:ff:ff:ff:ff")); + EXPECT_TRUE(mc_route != NULL); + RouteExport::State *route_state = static_cast + (bgp_peer_->GetRouteExportState(mc_route->get_table_partition(), + mc_route)); + EXPECT_TRUE(route_state->fabric_multicast_exported_ == true); + EXPECT_TRUE(route_state->ingress_replication_exported_ == true); + + //L2 route present + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_) == true)); + //L3 route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, local_vm_ip4_, 32) == true)); + //Remote route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, remote_vm_ip4_, 32) == true)); + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, remote_vm_mac_, remote_vm_ip4_) == true)); + + //Ksync validation for local route + VrfKSyncObject *vrf1_obj = agent_->ksync()->vrf_ksync_obj();; + DBTableBase::ListenerId vrf_listener_id = vrf1_obj->vrf_listener_id(); + InetUnicastRouteEntry* local_vm_rt = RouteGet("vrf1", local_vm_ip4_, + 32); + BridgeRouteEntry* local_vm_l2_rt = L2RouteGet("vrf1", local_vm_mac_); + if (dhcp_external) { + WAIT_FOR(1000, 1000,( + (local_vm_l2_rt->FindMacVmBindingPath()->flood_dhcp() + == true))); + } else { + WAIT_FOR(1000, 1000, + (local_vm_l2_rt->FindMacVmBindingPath()->flood_dhcp() + == false)); + } + VrfEntry *vrf = local_vm_rt->vrf(); + AgentRouteTable *vrf_l2_table = + static_cast(vrf->GetBridgeRouteTable()); + InetUnicastAgentRouteTable *vrf_uc_table = + static_cast + (vrf->GetInet4UnicastRouteTable()); + VrfKSyncObject::VrfState *l3_state = + static_cast + (vrf->GetState(vrf_uc_table, vrf_listener_id)); + VrfKSyncObject::VrfState *l2_state = + static_cast + (vrf->GetState(vrf_l2_table, vrf_listener_id)); + RouteKSyncObject *vrf_rt_obj = l3_state->inet4_uc_route_table_; + RouteKSyncObject *vrf_l2_rt_obj = l2_state->bridge_route_table_; + std::auto_ptr ksync(new RouteKSyncEntry(vrf_rt_obj, + local_vm_rt)); + std::auto_ptr l2_ksync(new RouteKSyncEntry(vrf_l2_rt_obj, + local_vm_l2_rt)); + ksync->BuildArpFlags(local_vm_rt, local_vm_rt->GetActivePath(), + local_vm_mac_); + l2_ksync->BuildArpFlags(local_vm_l2_rt, local_vm_l2_rt->GetActivePath(), + MacAddress()); + EXPECT_TRUE(ksync->proxy_arp()); + EXPECT_FALSE(ksync->flood()); + EXPECT_TRUE(vrf1_obj->RouteNeedsMacBinding(local_vm_rt)); + EXPECT_TRUE(vrf1_obj->GetIpMacBinding(local_vm_rt->vrf(), local_vm_ip4_) + != MacAddress()); + EXPECT_FALSE(l2_ksync->proxy_arp()); + EXPECT_FALSE(l2_ksync->flood()); + + //Ksync validation for remote route + InetUnicastRouteEntry* remote_vm_rt = RouteGet("vrf1", remote_vm_ip4_, + 32); + BridgeRouteEntry* remote_vm_l2_rt = L2RouteGet("vrf1", remote_vm_mac_); + //TODO mac vm binding path should get installed by evpn + //if (dhcp_external) { + // WAIT_FOR(1000, 1000,( + // (remote_vm_l2_rt->FindMacVmBindingPath()->flood_dhcp() + // == true))); + //} else { + // WAIT_FOR(1000, 1000, + // (remote_vm_l2_rt->FindMacVmBindingPath()->flood_dhcp() + // == false)); + //} + std::auto_ptr remote_ksync(new RouteKSyncEntry(vrf_rt_obj, + remote_vm_rt)); + std::auto_ptr remote_l2_ksync(new RouteKSyncEntry(vrf_l2_rt_obj, + remote_vm_l2_rt)); + remote_ksync->BuildArpFlags(remote_vm_rt, remote_vm_rt->GetActivePath(), + remote_vm_mac_); + l2_ksync->BuildArpFlags(remote_vm_l2_rt, remote_vm_l2_rt->GetActivePath(), + MacAddress()); + EXPECT_TRUE(remote_ksync->proxy_arp()); + EXPECT_FALSE(remote_ksync->flood()); + EXPECT_TRUE(vrf1_obj->RouteNeedsMacBinding(remote_vm_rt)); + EXPECT_TRUE(vrf1_obj->GetIpMacBinding(remote_vm_rt->vrf(), remote_vm_ip4_) + != MacAddress()); + EXPECT_FALSE(remote_l2_ksync->proxy_arp()); + EXPECT_FALSE(remote_l2_ksync->flood()); + VerifyVmInterfaceDhcp(); + } + + void VerifyL2OnlyMode() { + //First verify multicast + MulticastGroupObject *obj = + MulticastHandler::GetInstance()->FindFloodGroupObject("vrf1"); + EXPECT_TRUE(obj != NULL); + BridgeRouteEntry *mc_route = + L2RouteGet(vrf_name_, MacAddress::FromString("ff:ff:ff:ff:ff:ff")); + EXPECT_TRUE(mc_route != NULL); + RouteExport::State *route_state = static_cast + (bgp_peer_->GetRouteExportState(mc_route->get_table_partition(), + mc_route)); + EXPECT_TRUE(route_state->fabric_multicast_exported_ == true); + EXPECT_TRUE(route_state->ingress_replication_exported_ == true); + + //L2 route present + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_) == true)); + //L3 route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, local_vm_ip4_, 32) == false)); + //Remote route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, remote_vm_ip4_, 32) == true)); + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, remote_vm_mac_, remote_vm_ip4_) == true)); + + //Ksync validation + VrfKSyncObject *vrf1_obj = agent_->ksync()->vrf_ksync_obj();; + DBTableBase::ListenerId vrf_listener_id = vrf1_obj->vrf_listener_id(); + BridgeRouteEntry* local_vm_rt = L2RouteGet("vrf1", local_vm_mac_); + VrfEntry *vrf = local_vm_rt->vrf(); + AgentRouteTable *vrf_l2_table = + static_cast(vrf->GetBridgeRouteTable()); + VrfKSyncObject::VrfState *state = + static_cast + (vrf->GetState(vrf_l2_table, vrf_listener_id)); + RouteKSyncObject *vrf_rt_obj = state->bridge_route_table_; + std::auto_ptr ksync(new RouteKSyncEntry(vrf_rt_obj, + local_vm_rt)); + ksync->BuildArpFlags(local_vm_rt, local_vm_rt->GetActivePath(), + MacAddress()); + EXPECT_FALSE(ksync->proxy_arp()); + EXPECT_FALSE(ksync->flood()); + + //Ksync validation for remote route + VrfKSyncObject::VrfState *l2_state = + static_cast + (vrf->GetState(vrf_l2_table, vrf_listener_id)); + RouteKSyncObject *vrf_l2_rt_obj = l2_state->bridge_route_table_; + InetUnicastRouteEntry* remote_vm_rt = RouteGet("vrf1", remote_vm_ip4_, + 32); + BridgeRouteEntry* remote_vm_l2_rt = L2RouteGet("vrf1", remote_vm_mac_); + std::auto_ptr remote_ksync(new RouteKSyncEntry(vrf_rt_obj, + remote_vm_rt)); + std::auto_ptr remote_l2_ksync(new RouteKSyncEntry(vrf_l2_rt_obj, + remote_vm_l2_rt)); + remote_ksync->BuildArpFlags(remote_vm_rt, remote_vm_rt->GetActivePath(), + remote_vm_mac_); + remote_l2_ksync->BuildArpFlags(remote_vm_l2_rt, remote_vm_l2_rt->GetActivePath(), + MacAddress()); + EXPECT_FALSE(remote_ksync->proxy_arp()); + EXPECT_TRUE(remote_ksync->flood()); + //Since proxy is false, does not matter if mac binding is needed. + EXPECT_TRUE(vrf1_obj->RouteNeedsMacBinding(remote_vm_rt)); + EXPECT_FALSE(remote_l2_ksync->proxy_arp()); + EXPECT_FALSE(remote_l2_ksync->flood()); + + //interface validation + VerifyVmInterfaceDhcp(); + } + + void VerifyL3OnlyMode() { + //First verify multicast + MulticastGroupObject *obj = + MulticastHandler::GetInstance()->FindFloodGroupObject("vrf1"); + EXPECT_TRUE(obj != NULL); + BridgeRouteEntry *mc_route = + L2RouteGet(vrf_name_, MacAddress::FromString("ff:ff:ff:ff:ff:ff")); + EXPECT_TRUE(mc_route != NULL); + RouteExport::State *route_state = static_cast + (bgp_peer_->GetRouteExportState(mc_route->get_table_partition(), + mc_route)); + WAIT_FOR(1000, 1000, (route_state->fabric_multicast_exported_ == true)); + WAIT_FOR(1000, 1000, (route_state->ingress_replication_exported_ == false)); + + //L2 route present + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_) == false)); + //L3 route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, local_vm_ip4_, 32) == true)); + //Remote route present + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, remote_vm_ip4_, 32) == true)); + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, remote_vm_mac_, remote_vm_ip4_) == true)); + + //Ksync validation + VrfKSyncObject *vrf1_obj = agent_->ksync()->vrf_ksync_obj();; + DBTableBase::ListenerId vrf_listener_id = vrf1_obj->vrf_listener_id(); + InetUnicastRouteEntry* local_vm_rt = RouteGet("vrf1", local_vm_ip4_, + 32); + VrfEntry *vrf = local_vm_rt->vrf(); + InetUnicastAgentRouteTable *vrf_uc_table = + static_cast + (vrf->GetInet4UnicastRouteTable()); + VrfKSyncObject::VrfState *state = + static_cast + (vrf->GetState(vrf_uc_table, vrf_listener_id)); + RouteKSyncObject *vrf_rt_obj = state->inet4_uc_route_table_; + std::auto_ptr ksync(new RouteKSyncEntry(vrf_rt_obj, + local_vm_rt)); + EXPECT_FALSE(vrf1_obj->RouteNeedsMacBinding(local_vm_rt)); + ksync->BuildArpFlags(local_vm_rt, local_vm_rt->GetActivePath(), + MacAddress()); + EXPECT_TRUE(ksync->proxy_arp()); + EXPECT_FALSE(ksync->flood()); + EXPECT_TRUE(ksync->mac() == MacAddress::FromString("00:00:00:00:00:00")); + VerifyVmInterfaceDhcp(); + } + + void WaitForSetup(std::string type) { + if (type == "l2_l3") { + WAIT_FOR(1000, 100, (VmPortL2Active(input, 0) == true)); //l2 active + WAIT_FOR(1000, 100, (VmPortActive(input, 0) == true)); //v4 active + } else if (type == "l2") { + WAIT_FOR(1000, 100, (VmPortL2Active(input, 0) == true)); //l2 active + EXPECT_TRUE(VmPortActive(input, 0) == false); + } else if (type == "l3") { + WAIT_FOR(1000, 100, (VmPortActive(input, 0) == true)); //v4 active + EXPECT_TRUE(VmPortL2Active(input, 0) == false); + } + } + + void SetupSingleVmEnvironment(std::string setup_type, + bool global_config = false, + std::string global_type = "l2_l3") { + client->Reset(); + //Add Ipam + if (dhcp_external) + AddIPAM("vn1", ipam_info_dhcp_disable, 1); + else + AddIPAM("vn1", ipam_info_dhcp_enable, 1); + client->WaitForIdle(); + + if (setup_type == "l2_l3") { + CreateVmportEnv(input, 1); + } else if (setup_type == "l2") { + CreateL2VmportEnv(input, 1); + } else if (setup_type == "l3") { + CreateL3VmportEnv(input, 1); + } + + //Expect l3vpn or evpn route irrespective of forwarding mode. + AddRemoteVmRoute(remote_vm_mac_, remote_vm_ip4_, server1_ip_, + 200, (TunnelType::AllType())); + client->WaitForIdle(); + + if (global_config) { + WaitForSetup(global_type); + } else { + WaitForSetup(setup_type); + } + client->WaitForIdle(); + } + + void DeleteSingleVmEnvironment() { + //Time for deletion + DelIPAM("vn1"); + client->WaitForIdle(); + DeleteVmportEnv(input, 1, true); + client->WaitForIdle(); + DeleteRoute(bgp_peer_, vrf_name_, remote_vm_mac_, remote_vm_ip4_); + client->WaitForIdle(); + + WAIT_FOR(1000, 100, + (RouteFind(vrf_name_, local_vm_ip4_, 32) == false)); + WAIT_FOR(1000, 100, + (L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_) == false)); + EXPECT_FALSE(VmPortFind(input, 0)); + client->WaitForIdle(); + } + + std::string vrf_name_; + std::string eth_name_; + Ip4Address default_dest_ip_; + + char local_vm_mac_str_[100]; + MacAddress local_vm_mac_; + char local_vm_ip4_str_[100]; + Ip4Address local_vm_ip4_; + char local_vm_ip6_str_[100]; + IpAddress local_vm_ip6_; + + char remote_vm_mac_str_[100]; + MacAddress remote_vm_mac_; + char remote_vm_ip4_str_[100]; + Ip4Address remote_vm_ip4_; + char remote_vm_ip6_str_[100]; + IpAddress remote_vm_ip6_; + + Ip4Address vhost_ip_; + Ip4Address server1_ip_; + Ip4Address server2_ip_; + + BgpPeer *bgp_peer_; + Agent *agent_; +}; + +TEST_F(ForwardingModeTest, dummy) { +} + +//VN forwarding mode tests +TEST_F(ForwardingModeTest, default_forwarding_mode_l2_l3_with_none_configure) { + GlobalForwardingMode("l2_l3"); + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +//With l2_l3 in environment VN gets set with blank forwarding mode. +//This in turn defaults to l2_l3. +//This test case explicitly modifies blank forwarding mode +//to l2_l3 and verify. +TEST_F(ForwardingModeTest, default_forwarding_mode_l2_l3_configured) { + SetupSingleVmEnvironment("l2_l3"); + ModifyForwardingModeVn("vn1", 1, "l2_l3"); + client->WaitForIdle(); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, default_forwarding_mode_l2) { + SetupSingleVmEnvironment("l2"); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, default_forwarding_mode_l3) { + SetupSingleVmEnvironment("l3"); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l2_l3_to_l2) { + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + SetupSingleVmEnvironment("l2"); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l2_l3_to_l3) { + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + SetupSingleVmEnvironment("l3"); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l2_to_l2_l3) { + SetupSingleVmEnvironment("l2"); + VerifyL2OnlyMode(); + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l2_to_l3) { + SetupSingleVmEnvironment("l2"); + VerifyL2OnlyMode(); + SetupSingleVmEnvironment("l3"); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l3_to_l2_l3) { + SetupSingleVmEnvironment("l3"); + VerifyL3OnlyMode(); + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, change_forwarding_mode_l3_to_l2) { + SetupSingleVmEnvironment("l3"); + VerifyL3OnlyMode(); + SetupSingleVmEnvironment("l2"); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +//Global vrouter forwarding mode config tests +TEST_F(ForwardingModeTest, global_default_to_empty) { + GlobalForwardingMode(""); + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_default_to_l2_l3) { + GlobalForwardingMode("l2_l3"); + SetupSingleVmEnvironment("l2_l3"); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_default_to_l2) { + GlobalForwardingMode("l2"); + SetupSingleVmEnvironment("l2_l3", true, "l2"); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_default_to_l3) { + GlobalForwardingMode("l3"); + SetupSingleVmEnvironment("l2_l3", true, "l3"); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l2_l3_to_l2) { + GlobalForwardingMode("l2_l3"); + SetupSingleVmEnvironment("l2_l3", true, "l2_l3"); + //Toggle + GlobalForwardingMode("l2"); + client->WaitForIdle(); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l2_l3_to_l3) { + GlobalForwardingMode("l2_l3"); + SetupSingleVmEnvironment("l2_l3", true, "l2_l3"); + //Toggle + GlobalForwardingMode("l3"); + client->WaitForIdle(); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l2_to_l2_l3) { + GlobalForwardingMode("l2"); + SetupSingleVmEnvironment("l2_l3", true, "l2"); + //Toggle + GlobalForwardingMode("l2_l3"); + client->WaitForIdle(); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l3_to_l2_l3) { + GlobalForwardingMode("l3"); + SetupSingleVmEnvironment("l2_l3", true, "l3"); + //Toggle + GlobalForwardingMode("l2_l3"); + client->WaitForIdle(); + VerifyL2L3Mode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l3_to_l2) { + GlobalForwardingMode("l3"); + SetupSingleVmEnvironment("l2_l3", true, "l3"); + //Toggle + GlobalForwardingMode("l2"); + client->WaitForIdle(); + VerifyL2OnlyMode(); + DeleteSingleVmEnvironment(); +} + +TEST_F(ForwardingModeTest, global_change_l2_to_l3) { + GlobalForwardingMode("l2"); + SetupSingleVmEnvironment("l2_l3", true, "l2"); + //Toggle + GlobalForwardingMode("l3"); + client->WaitForIdle(); + VerifyL3OnlyMode(); + DeleteSingleVmEnvironment(); +} + +int main(int argc, char *argv[]) { + ::testing::InitGoogleTest(&argc, argv); + GETUSERARGS(); + client = TestInit(init_file, ksync_init, true, false); + eth_itf = Agent::GetInstance()->fabric_interface_name(); + + int ret = 0; + //Run tests with dhcp server as external + dhcp_external = true; + ret += RUN_ALL_TESTS(); + client->WaitForIdle(); + //Run tests with agent as dhcp server + dhcp_external = false; + ret += RUN_ALL_TESTS(); + + client->WaitForIdle(); + TestShutdown(); + delete client; + return ret; +} + diff --git a/src/vnsw/agent/test/test_l2route.cc b/src/vnsw/agent/test/test_l2route.cc index ac75041fc21..7f1e7df4e6f 100644 --- a/src/vnsw/agent/test/test_l2route.cc +++ b/src/vnsw/agent/test/test_l2route.cc @@ -241,7 +241,6 @@ TEST_F(RouteTest, LocalVmRoute_1) { MulticastGroupObject *obj = MulticastHandler::GetInstance()->FindFloodGroupObject("vrf1"); EXPECT_TRUE(obj != NULL); - EXPECT_TRUE(obj->bridging() == true); WAIT_FOR(1000, 100, (L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_) == true)); BridgeRouteEntry *rt = L2RouteGet(vrf_name_, local_vm_mac_, local_vm_ip4_); @@ -318,7 +317,6 @@ TEST_F(RouteTest, Mpls_sandesh_check_with_l2route) { MulticastGroupObject *obj = MulticastHandler::GetInstance()->FindFloodGroupObject("vrf1"); EXPECT_TRUE(obj != NULL); - EXPECT_TRUE(obj->bridging() == true); EXPECT_TRUE(L2RouteFind(vrf_name_, local_vm_mac_, local_vm_ip4_)); MplsReq *mpls_list_req = new MplsReq(); diff --git a/src/vnsw/agent/test/test_multicast.cc b/src/vnsw/agent/test/test_multicast.cc index 3ce04a4727d..e4623b9fed7 100644 --- a/src/vnsw/agent/test/test_multicast.cc +++ b/src/vnsw/agent/test/test_multicast.cc @@ -852,10 +852,6 @@ TEST_F(MulticastTest, subnet_bcast_ipv4_vn_delete) { client->WaitForIdle(); WAIT_FOR(1000, 1000, (RouteFind("vrf1", "11.1.1.255", 32))); - //Change the vn forwarding mode to l2-only - MulticastGroupObject *mcobj = MulticastHandler::GetInstance()-> - FindGroupObject("vrf1", IpAddress::from_string("11.1.1.255").to_v4()); - EXPECT_TRUE(mcobj->bridging() == false); //Del VN VnDelReq(1); client->WaitForIdle(); @@ -910,10 +906,6 @@ TEST_F(MulticastTest, subnet_bcast_ipv4_vn_ipam_change) { client->WaitForIdle(); WAIT_FOR(1000, 1000, (RouteFind("vrf1", "11.1.1.255", 32))); - //Change the vn forwarding mode to l2-only - MulticastGroupObject *mcobj = MulticastHandler::GetInstance()-> - FindGroupObject("vrf1", IpAddress::from_string("11.1.1.255").to_v4()); - EXPECT_TRUE(mcobj->bridging() == false); //Change IPAM AddIPAM("vn1", ipam_info_2, 2); client->WaitForIdle(); @@ -963,10 +955,6 @@ TEST_F(MulticastTest, subnet_bcast_ipv4_vn_vrf_link_delete) { client->WaitForIdle(); WAIT_FOR(1000, 1000, (RouteFind("vrf1", "11.1.1.255", 32))); - //Change the vn forwarding mode to l2-only - MulticastGroupObject *mcobj = MulticastHandler::GetInstance()-> - FindGroupObject("vrf1", IpAddress::from_string("11.1.1.255").to_v4()); - EXPECT_TRUE(mcobj->bridging() == false); //VRF delete for VN DelLink("virtual-network", "vn1", "routing-instance", "vrf1"); client->WaitForIdle(); @@ -1016,11 +1004,6 @@ TEST_F(MulticastTest, subnet_bcast_add_l2l3vn_and_l2vn) { client->WaitForIdle(); WAIT_FOR(1000, 1000, (RouteFind("vrf1", "11.1.1.255", 32))); - MulticastGroupObject *mcobj = MulticastHandler::GetInstance()-> - FindGroupObject("vrf1", IpAddress::from_string("11.1.1.255").to_v4()); - EXPECT_TRUE(mcobj->bridging() == false); - client->WaitForIdle(); - AddL2Vn("vn2", 2); client->WaitForIdle(); EXPECT_TRUE(RouteFind("vrf1", "11.1.1.255", 32)); diff --git a/src/vnsw/agent/test/test_util.cc b/src/vnsw/agent/test/test_util.cc index 1075e800e06..ff4318b0b39 100644 --- a/src/vnsw/agent/test/test_util.cc +++ b/src/vnsw/agent/test/test_util.cc @@ -1548,6 +1548,27 @@ void ModifyForwardingModeVn(const string &name, int id, const string &fw_mode) { AddNode("virtual-network", name.c_str(), id, str.str().c_str()); } +void AddL3Vn(const char *name, int id) { + std::stringstream str; + str << "" << endl; + str << " l3" << endl; + str << "" << endl; + str << "" << id << "" << endl; + + AddNode("virtual-network", name, id, str.str().c_str()); +} + +void AddL2L3Vn(const char *name, int id, bool admin_state) { + std::stringstream str; + str << "" << endl; + str << " " << (id+100) << "" << endl; + str << " l2_l3" << endl; + str << "" << endl; + str << "" << id << "" << endl; + + AddNode("virtual-network", name, id, str.str().c_str(), admin_state); +} + void AddL2Vn(const char *name, int id) { std::stringstream str; str << "" << endl; @@ -1564,7 +1585,6 @@ void AddVn(const char *name, int id, bool admin_state) { std::stringstream str; str << "" << endl; str << " " << (id+100) << "" << endl; - str << " l2_l3" << endl; str << " enable" << endl; str << "" << endl; str << "" << id << "" << endl; @@ -2048,6 +2068,12 @@ void VxLanNetworkIdentifierMode(bool config) { AddNode("global-vrouter-config", "vrouter-config", 1, str.str().c_str()); } +void GlobalForwardingMode(std::string mode) { + std::stringstream str; + str << "" << mode << "" << endl; + AddNode("global-vrouter-config", "vrouter-config", 1, str.str().c_str()); +} + void AddEncapList(const char *encap1, const char *encap2, const char *encap3) { std::stringstream str; str << "" << endl; @@ -2552,6 +2578,20 @@ void CreateVmportEnv(struct PortInfo *input, int count, int acl_id, void CreateL2VmportEnv(struct PortInfo *input, int count, int acl_id, const char *vn, const char *vrf) { + AddL2Vn("vn1", 1); + AddVrf("vrf1"); + AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); + TestClient::WaitForIdle(); + CreateVmportEnvInternal(input, count, acl_id, vn, vrf, NULL, true, + true, false, true); +} + +void CreateL3VmportEnv(struct PortInfo *input, int count, int acl_id, + const char *vn, const char *vrf) { + AddL3Vn("vn1", 1); + AddVrf("vrf1"); + AddLink("virtual-network", "vn1", "routing-instance", "vrf1"); + TestClient::WaitForIdle(); CreateVmportEnvInternal(input, count, acl_id, vn, vrf, NULL, true, true, false, true); } @@ -3330,11 +3370,12 @@ BgpPeer *CreateBgpPeer(std::string addr, std::string name) { BgpPeer *CreateBgpPeer(const Ip4Address &addr, std::string name) { XmppChannelMock *xmpp_channel = new XmppChannelMock(); AgentXmppChannel *channel; - Agent::GetInstance()->set_controller_ifmap_xmpp_server(addr.to_string(), 0); + Agent::GetInstance()->set_controller_ifmap_xmpp_server(addr.to_string(), 1); channel = new AgentXmppChannel(Agent::GetInstance(), - "XMPP Server", "", 0); + "XMPP Server", "", 1); channel->RegisterXmppChannel(xmpp_channel); + Agent::GetInstance()->set_controller_xmpp_channel(channel, 1); AgentXmppChannel::HandleAgentXmppClientChannelEvent(channel, xmps::READY); client->WaitForIdle(); return channel->bgp_peer_id(); diff --git a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc index 60d1aa5a179..d2d456368cf 100644 --- a/src/vnsw/agent/vrouter/ksync/interface_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/interface_ksync.cc @@ -41,6 +41,7 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, const InterfaceKSyncEntry *entry, uint32_t index) : KSyncNetlinkDBEntry(index), analyzer_name_(entry->analyzer_name_), + dhcp_enable_(entry->dhcp_enable_), fd_(kInvalidIndex), flow_key_nh_id_(entry->flow_key_nh_id_), has_service_vlan_(entry->has_service_vlan_), @@ -78,6 +79,7 @@ InterfaceKSyncEntry::InterfaceKSyncEntry(InterfaceKSyncObject *obj, const Interface *intf) : KSyncNetlinkDBEntry(kInvalidIndex), analyzer_name_(), + dhcp_enable_(true), fd_(-1), flow_key_nh_id_(0), has_service_vlan_(false), @@ -207,6 +209,11 @@ bool InterfaceKSyncEntry::Sync(DBEntry *e) { ret = true; } + if (dhcp_enable_ != vm_port->dhcp_enabled()) { + dhcp_enable_ = vm_port->dhcp_enabled(); + ret = true; + } + if (vm_port->do_dhcp_relay()) { if (ip_ != vm_port->ip_addr().to_ulong()) { ip_ = vm_port->ip_addr().to_ulong(); @@ -479,6 +486,9 @@ int InterfaceKSyncEntry::Encode(sandesh_op::type op, char *buf, int buf_len) { case Interface::VM_INTERFACE: { if (vmi_device_type_ == VmInterface::TOR) return 0; + if (dhcp_enable_) { + flags |= VIF_FLAG_DHCP_ENABLED; + } if (bridging_) { flags |= VIF_FLAG_L2_ENABLED; } diff --git a/src/vnsw/agent/vrouter/ksync/interface_ksync.h b/src/vnsw/agent/vrouter/ksync/interface_ksync.h index 595494e9616..3e4bebab522 100644 --- a/src/vnsw/agent/vrouter/ksync/interface_ksync.h +++ b/src/vnsw/agent/vrouter/ksync/interface_ksync.h @@ -65,6 +65,10 @@ class InterfaceKSyncEntry : public KSyncNetlinkDBEntry { virtual int DeleteMsg(char *buf, int buf_len); virtual KSyncEntry *UnresolvedReference(); void FillObjectLog(sandesh_op::type op, KSyncIntfInfo &info) const; + bool dhcp_enable() const {return dhcp_enable_;} + bool layer3_forwarding() const {return layer3_forwarding_;} + bool bridging() const {return bridging_;} + private: friend class InterfaceKSyncObject; int Encode(sandesh_op::type op, char *buf, int buf_len); diff --git a/src/vnsw/agent/vrouter/ksync/route_ksync.cc b/src/vnsw/agent/vrouter/ksync/route_ksync.cc index cd18a0e8e52..3e1d7fca9e5 100644 --- a/src/vnsw/agent/vrouter/ksync/route_ksync.cc +++ b/src/vnsw/agent/vrouter/ksync/route_ksync.cc @@ -306,6 +306,8 @@ bool RouteKSyncEntry::BuildArpFlags(const DBEntry *e, const AgentPath *path, if (rt->FindLocalVmPortPath()) { // Local port without MAC stitching should only be a transition // case. In the meanwhile, flood ARP so that VM can respond + // Note: In case VN is in L3 forwarding mode flags will be reset. + // This is done below when VN entry is extracted. proxy_arp_ = false; flood = true; } else { @@ -318,12 +320,22 @@ bool RouteKSyncEntry::BuildArpFlags(const DBEntry *e, const AgentPath *path, // If the route crosses a VN, we want packet to be routed. So, override // the flags set above and set only Proxy flag + // When L2 forwarding mode is disabled, reset the proxy arp to true and flood + // of arp to false. VnEntry *vn= rt->vrf()->vn(); - if (vn == NULL || (path->dest_vn_name() != vn->GetName())) { + if (vn == NULL || (path->dest_vn_name() != vn->GetName()) || + (vn->bridging() == false)) { proxy_arp = true; flood = false; } + //If VN is running in l2 mode, then any l3 route installed should + //have flood flag set for ARP. + if (vn && (vn->layer3_forwarding() == false)) { + proxy_arp = false; + flood = true; + } + // VRouter does not honour flood/proxy_arp flags for fabric-vrf if (rt->vrf()->GetName() == agent->fabric_vrf_name()) { proxy_arp = false; @@ -415,7 +427,7 @@ bool RouteKSyncEntry::Sync(DBEntry *e) { VrfKSyncObject *obj = ksync_obj_->ksync()->vrf_ksync_obj(); const InetUnicastRouteEntry *uc_rt = static_cast(e); - MacAddress mac; + MacAddress mac = MacAddress::ZeroMac(); if (obj->RouteNeedsMacBinding(uc_rt)) { mac = obj->GetIpMacBinding(uc_rt->vrf(), addr_); } @@ -434,8 +446,7 @@ bool RouteKSyncEntry::Sync(DBEntry *e) { static_cast(route); //First search for v4 - const MacVmBindingPath *dhcp_path = dynamic_cast - (l2_rt->FindMacVmBindingPath()); + const MacVmBindingPath *dhcp_path = l2_rt->FindMacVmBindingPath(); bool flood_dhcp = true; // Flood DHCP if MacVmBindingPath is not present if (dhcp_path) flood_dhcp = dhcp_path->flood_dhcp(); @@ -862,6 +873,11 @@ bool VrfKSyncObject::RouteNeedsMacBinding(const InetUnicastRouteEntry *rt) { if (rt->addr().is_v6() && rt->plen() != 128) return false; + //Check if VN is enabled for bridging, if not then skip mac binding. + VnEntry *vn= rt->vrf()->vn(); + if (vn == NULL || (vn->bridging() == false)) + return false; + const NextHop *nh = rt->GetActiveNextHop(); if (nh == NULL) return false;