From 6b46e72b0bfb81ba8a0d2e448976d8d606ff6ae6 Mon Sep 17 00:00:00 2001 From: Manish Date: Tue, 4 Aug 2015 01:47:26 +0530 Subject: [PATCH] Add support for l3 mode in agent. There are three forwarding modes at VN level and global level- l2_l3(IRB), l3 only(v4+v6), l2 only. VN level configuration is always at highest priority. In case VN level forwarding mode is not configured then global mode is consulted. For multicast store the knowledge of bridging enabled in local peer path. This helps in identifying if EVPN/TOR subscription/withdraw needs to be sent. Partial-Bug: 1471637 (cherry picked from commit c87a0cf76778d083082ddf19ac79bc9fdb7fec1a) Conflicts: src/vnsw/agent/oper/vn.cc src/vnsw/agent/oper/vn.h Change-Id: I03f5a883f39c7bc47f7adb8feb1cef949e746755 --- src/vnsw/agent/cmn/agent.cc | 12 + src/vnsw/agent/cmn/agent.h | 8 + .../agent/controller/controller_export.cc | 238 +++--- src/vnsw/agent/controller/controller_export.h | 20 +- src/vnsw/agent/kstate/test/test_kstate.cc | 9 +- src/vnsw/agent/oper/SConscript | 2 +- src/vnsw/agent/oper/agent_path.cc | 2 +- src/vnsw/agent/oper/agent_path.h | 8 +- ...t_route_encap.cc => agent_route_resync.cc} | 8 +- ...ent_route_encap.h => agent_route_resync.h} | 12 +- src/vnsw/agent/oper/agent_route_walker.cc | 1 - src/vnsw/agent/oper/bridge_route.cc | 7 +- src/vnsw/agent/oper/bridge_route.h | 4 +- src/vnsw/agent/oper/global_vrouter.cc | 33 +- src/vnsw/agent/oper/global_vrouter.h | 6 +- src/vnsw/agent/oper/interface.cc | 19 +- src/vnsw/agent/oper/interface.h | 2 +- src/vnsw/agent/oper/multicast.cc | 62 +- src/vnsw/agent/oper/multicast.h | 18 +- src/vnsw/agent/oper/operdb_init.cc | 1 - src/vnsw/agent/oper/test/test_intf.cc | 2 +- src/vnsw/agent/oper/vm_interface.cc | 132 ++-- src/vnsw/agent/oper/vm_interface.h | 52 +- src/vnsw/agent/oper/vn.cc | 96 ++- src/vnsw/agent/oper/vn.h | 20 +- .../test/test_ovs_multicast_local.cc | 8 +- src/vnsw/agent/pkt/test/egress-flow.xml | 8 +- src/vnsw/agent/pkt/test/l2-sg-flow.xml | 12 +- src/vnsw/agent/pkt/test/test_xml_packet_ut.cc | 8 +- .../agent/pkt/test/unknown-unicast-flood.xml | 6 +- src/vnsw/agent/test/SConscript | 1 + src/vnsw/agent/test/test_cmn_util.h | 5 + src/vnsw/agent/test/test_forwarding_mode.cc | 683 ++++++++++++++++++ src/vnsw/agent/test/test_l2route.cc | 2 - src/vnsw/agent/test/test_multicast.cc | 17 - src/vnsw/agent/test/test_util.cc | 47 +- .../agent/vrouter/ksync/interface_ksync.cc | 10 + .../agent/vrouter/ksync/interface_ksync.h | 4 + src/vnsw/agent/vrouter/ksync/route_ksync.cc | 24 +- 39 files changed, 1234 insertions(+), 375 deletions(-) rename src/vnsw/agent/oper/{agent_route_encap.cc => agent_route_resync.cc} (74%) rename src/vnsw/agent/oper/{agent_route_encap.h => agent_route_resync.h} (60%) create mode 100644 src/vnsw/agent/test/test_forwarding_mode.cc 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;