From 419ceb09471e766abd6e39cab42ea99ab50399e8 Mon Sep 17 00:00:00 2001 From: Manish Date: Mon, 17 Aug 2015 23:18:25 +0530 Subject: [PATCH] Add multicast route for handling mcast traffic to vhost. Both v4 and v6 mcast covering route is installed in fabric VRF. This takes care of mcast traffic over vhost interface. Closes-bug: 1485432 (cherry picked from commit 086c2383cbb7073a61f333d0705b600d1f909299) Conflicts: src/vnsw/agent/test/test_agent_route_walker.cc Change-Id: I929823a3e799f1f103fb59e6731086be62c3b6e4 --- src/vnsw/agent/cmn/agent.h | 3 + src/vnsw/agent/oper/inet_interface.cc | 62 ++++++++++++++----- src/vnsw/agent/oper/inet_interface.h | 2 + src/vnsw/agent/oper/inet_unicast_route.cc | 18 ++++-- src/vnsw/agent/oper/inet_unicast_route.h | 4 +- .../agent/test/test_agent_route_walker.cc | 10 +-- src/vnsw/agent/test/test_vn.cc | 35 +++++++++++ 7 files changed, 108 insertions(+), 26 deletions(-) diff --git a/src/vnsw/agent/cmn/agent.h b/src/vnsw/agent/cmn/agent.h index a88aae0f0f6..38a776ea014 100644 --- a/src/vnsw/agent/cmn/agent.h +++ b/src/vnsw/agent/cmn/agent.h @@ -191,6 +191,9 @@ extern void RouterIdDepInit(Agent *agent); #define METADATA_NAT_PORT 80 #define AGENT_INIT_TASKNAME "Agent::Init" #define AGENT_SHUTDOWN_TASKNAME "Agent::Shutdown" +#define IPV4_MULTICAST_BASE_ADDRESS "224.0.0.0" +#define IPV6_MULTICAST_BASE_ADDRESS "ff00::" +#define MULTICAST_BASE_ADDRESS_PLEN 8 #define VROUTER_SERVER_PORT 20914 diff --git a/src/vnsw/agent/oper/inet_interface.cc b/src/vnsw/agent/oper/inet_interface.cc index b7949187955..0ff313c33e9 100644 --- a/src/vnsw/agent/oper/inet_interface.cc +++ b/src/vnsw/agent/oper/inet_interface.cc @@ -224,6 +224,52 @@ static void DeleteHostRoutes(Agent *agent, InetUnicastAgentRouteTable *table, GetIp4SubnetBroadcastAddress(addr, plen), 32); } +void InetInterface::AddHostMulticastRoutes() { + VrfTable *vrf_table = static_cast(vrf()->get_table()); + InetUnicastAgentRouteTable *uc_rt_table = + (vrf_table->GetInet4UnicastRouteTable(vrf()->GetName())); + boost::system::error_code ec; + // Add v4 route for covering multicast + uc_rt_table-> + AddVHostRecvRoute(uc_rt_table->agent()->local_peer(), + vrf()->GetName(), + name_, + Ip4Address::from_string(IPV4_MULTICAST_BASE_ADDRESS, + ec), + MULTICAST_BASE_ADDRESS_PLEN, + vn_name_, + false); + // Add v6 route for covering multicast + uc_rt_table-> + AddVHostRecvRoute(uc_rt_table->agent()->local_peer(), + vrf()->GetName(), + name_, + Ip6Address::from_string(IPV6_MULTICAST_BASE_ADDRESS, + ec), + MULTICAST_BASE_ADDRESS_PLEN, + vn_name_, + false); +} + +void InetInterface::DelHostMulticastRoutes() { + VrfTable *vrf_table = static_cast(vrf()->get_table()); + InetUnicastAgentRouteTable *uc_rt_table = + (vrf_table->GetInet4UnicastRouteTable(vrf()->GetName())); + boost::system::error_code ec; + // Del v4 route for covering multicast + uc_rt_table->Delete(uc_rt_table->agent()->local_peer(), + vrf()->GetName(), + Ip4Address::from_string(IPV4_MULTICAST_BASE_ADDRESS, + ec), + MULTICAST_BASE_ADDRESS_PLEN); + // Del v6 route for covering multicast + uc_rt_table->Delete(uc_rt_table->agent()->local_peer(), + vrf()->GetName(), + Ip6Address::from_string(IPV6_MULTICAST_BASE_ADDRESS, + ec), + MULTICAST_BASE_ADDRESS_PLEN); +} + // Things to do to activate VHOST/LL interface // 1. Create the receive next-hops for interface (with policy and witout policy) // 2. Add routes needed to manage the IP address on interface @@ -243,19 +289,13 @@ void InetInterface::ActivateHostInterface() { AddHostRoutes(agent, uc_rt_table, vrf(), name(), xconnect_.get(), ip_addr_, plen_, vn_name_); } + AddHostMulticastRoutes(); if (gw_.to_ulong()) { AddDefaultRoute(agent, uc_rt_table, vrf(), xconnect_.get(), gw_, vn_name_); } - // Add receive-route for broadcast address - Inet4MulticastAgentRouteTable *mc_rt_table = - static_cast - (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); - mc_rt_table->AddVHostRecvRoute(vrf()->GetName(), name_, - Ip4Address(0xFFFFFFFF), false); - ReceiveNHKey nh_key(new InetInterfaceKey(name_), false); flow_key_nh_ = static_cast( agent->nexthop_table()->FindActiveEntry(&nh_key)); @@ -272,18 +312,12 @@ void InetInterface::DeActivateHostInterface() { DeleteHostRoutes(agent, uc_rt_table, vrf(), xconnect_.get(), ip_addr_, plen_); } + DelHostMulticastRoutes(); if (gw_.to_ulong()) { DeleteDefaultRoute(agent, uc_rt_table, vrf(), gw_); } - Inet4MulticastAgentRouteTable *mc_rt_table = - static_cast - (VrfTable::GetInstance()->GetInet4MulticastRouteTable(vrf()->GetName())); - // Add receive-route for broadcast address - mc_rt_table->Delete(vrf()->GetName(), Ip4Address(0), - Ip4Address(0xFFFFFFFF)); - // Delete receive nexthops ReceiveNH::Delete(agent->nexthop_table(), name_); flow_key_nh_ = NULL; diff --git a/src/vnsw/agent/oper/inet_interface.h b/src/vnsw/agent/oper/inet_interface.h index 5e84395c706..fcb20443b5d 100644 --- a/src/vnsw/agent/oper/inet_interface.h +++ b/src/vnsw/agent/oper/inet_interface.h @@ -50,6 +50,8 @@ class InetInterface : public Interface { void DeActivateSimpleGateway(); void ActivateHostInterface(); void DeActivateHostInterface(); + void AddHostMulticastRoutes(); + void DelHostMulticastRoutes(); // Helper functions static void Create(InterfaceTable *table, const std::string &ifname, diff --git a/src/vnsw/agent/oper/inet_unicast_route.cc b/src/vnsw/agent/oper/inet_unicast_route.cc index fe38af9838b..50d42b6a735 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.cc +++ b/src/vnsw/agent/oper/inet_unicast_route.cc @@ -1313,7 +1313,7 @@ void InetUnicastAgentRouteTable::AddInetInterfaceRouteReq(const Peer *peer, static void AddVHostRecvRouteInternal(DBRequest *req, const Peer *peer, const string &vrf, const string &interface, - const Ip4Address &addr, uint8_t plen, + const IpAddress &addr, uint8_t plen, const string &vn_name, bool policy) { req->oper = DBRequest::DB_ENTRY_ADD_CHANGE; req->key.reset(new InetUnicastRouteKey(peer, vrf, addr, plen)); @@ -1326,7 +1326,7 @@ static void AddVHostRecvRouteInternal(DBRequest *req, const Peer *peer, void InetUnicastAgentRouteTable::AddVHostRecvRoute(const Peer *peer, const string &vrf, const string &interface, - const Ip4Address &addr, + const IpAddress &addr, uint8_t plen, const string &vn_name, bool policy) { @@ -1334,17 +1334,25 @@ void InetUnicastAgentRouteTable::AddVHostRecvRoute(const Peer *peer, AddVHostRecvRouteInternal(&req, peer, vrf, interface, addr, plen, vn_name, policy); static_cast(req.data.get())->set_proxy_arp(); - Inet4UnicastTableProcess(Agent::GetInstance(), vrf, req); + if (addr.is_v4()) { + Inet4UnicastTableProcess(Agent::GetInstance(), vrf, req); + } else if (addr.is_v6()) { + Inet6UnicastTableProcess(Agent::GetInstance(), vrf, req); + } } void InetUnicastAgentRouteTable::AddVHostRecvRouteReq (const Peer *peer, const string &vrf, const string &interface, - const Ip4Address &addr, uint8_t plen, const string &vn_name, bool policy) { + const IpAddress &addr, uint8_t plen, const string &vn_name, bool policy) { DBRequest req; AddVHostRecvRouteInternal(&req, peer, vrf, interface, addr, plen, vn_name, policy); static_cast(req.data.get())->set_proxy_arp(); - Inet4UnicastTableEnqueue(Agent::GetInstance(), &req); + if (addr.is_v4()) { + Inet4UnicastTableEnqueue(Agent::GetInstance(), &req); + } else if (addr.is_v6()) { + Inet6UnicastTableEnqueue(Agent::GetInstance(), vrf, &req); + } } void diff --git a/src/vnsw/agent/oper/inet_unicast_route.h b/src/vnsw/agent/oper/inet_unicast_route.h index aef40625f78..ff6e49a5c7d 100644 --- a/src/vnsw/agent/oper/inet_unicast_route.h +++ b/src/vnsw/agent/oper/inet_unicast_route.h @@ -272,11 +272,11 @@ class InetUnicastAgentRouteTable : public AgentRouteTable { uint32_t label, const string &vn_name); static void AddVHostRecvRoute(const Peer *peer, const string &vrf, const string &interface, - const Ip4Address &addr, uint8_t plen, + const IpAddress &addr, uint8_t plen, const string &vn_name, bool policy); static void AddVHostRecvRouteReq(const Peer *peer, const string &vrf, const string &interface, - const Ip4Address &addr, uint8_t plen, + const IpAddress &addr, uint8_t plen, const string &vn_name, bool policy); static void AddVHostSubnetRecvRoute(const Peer *peer, const string &vrf, const string &interface, diff --git a/src/vnsw/agent/test/test_agent_route_walker.cc b/src/vnsw/agent/test/test_agent_route_walker.cc index fdadfef68c5..684af23e61d 100644 --- a/src/vnsw/agent/test/test_agent_route_walker.cc +++ b/src/vnsw/agent/test/test_agent_route_walker.cc @@ -199,7 +199,7 @@ class AgentRouteWalkerTest : public AgentRouteWalker, public ::testing::Test { uint32_t vrf_notifications_count, uint32_t total_rt_vrf_walk_done) { client->WaitForIdle(10); - WAIT_FOR(100, 1000, (route_notifications == route_notifications_)); + WAIT_FOR(100, 1000, (route_notifications_ == route_notifications_)); ASSERT_TRUE(route_notifications_ == route_notifications); ASSERT_TRUE(vrf_notifications_ == vrf_notifications); ASSERT_TRUE(vrf_notifications_count_ == vrf_notifications_count); @@ -266,7 +266,7 @@ TEST_F(AgentRouteWalkerTest, walk_all_routes_wih_no_vrf) { client->Reset(); SetupEnvironment(0); StartVrfWalk(); - VerifyNotifications(8, 1, 1, Agent::ROUTE_TABLE_MAX - 1); + VerifyNotifications(9, 1, 1, Agent::ROUTE_TABLE_MAX - 1); EXPECT_TRUE(walk_task_context_mismatch_ == false); walk_task_context_mismatch_ = true; DeleteEnvironment(0); @@ -276,7 +276,7 @@ TEST_F(AgentRouteWalkerTest, walk_all_routes_wih_1_vrf) { client->Reset(); SetupEnvironment(1); StartVrfWalk(); - VerifyNotifications(18, 2, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 2)); + VerifyNotifications(19, 2, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 2)); EXPECT_TRUE(walk_task_context_mismatch_ == false); walk_task_context_mismatch_ = true; DeleteEnvironment(1); @@ -286,7 +286,7 @@ TEST_F(AgentRouteWalkerTest, walk_all_routes_with_2_vrf) { client->Reset(); SetupEnvironment(2); StartVrfWalk(); - VerifyNotifications(28, 3, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 3)); + VerifyNotifications(29, 3, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 3)); EXPECT_TRUE(walk_task_context_mismatch_ == false); walk_task_context_mismatch_ = true; DeleteEnvironment(2); @@ -296,7 +296,7 @@ TEST_F(AgentRouteWalkerTest, walk_all_routes_with_3_vrf) { client->Reset(); SetupEnvironment(3); StartVrfWalk(); - VerifyNotifications(38, 4, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 4)); + VerifyNotifications(39, 4, 1, ((Agent::ROUTE_TABLE_MAX - 1) * 4)); EXPECT_TRUE(walk_task_context_mismatch_ == false); walk_task_context_mismatch_ = true; DeleteEnvironment(3); diff --git a/src/vnsw/agent/test/test_vn.cc b/src/vnsw/agent/test/test_vn.cc index 856ee9b4f44..8e62a4c9818 100644 --- a/src/vnsw/agent/test/test_vn.cc +++ b/src/vnsw/agent/test/test_vn.cc @@ -953,6 +953,41 @@ TEST_F(CfgTest, CfgUuidChange) { } +TEST_F(CfgTest, multicast_fabric_routes) { + //Send control node message on subnet bcast after family has changed to L2 + client->Reset(); + struct PortInfo input[] = { + {"vnet1", 1, "11.1.1.2", "00:00:00:01:01:11", 1, 1}, + }; + + IpamInfo ipam_info[] = { + {"11.1.1.0", 24, "11.1.1.200", true}, + }; + + CreateVmportEnv(input, 1, 0); + client->WaitForIdle(); + + WAIT_FOR(1000, 1000, (VmPortActive(input, 0) == true)); + + AddIPAM("vn1", ipam_info, 1); + client->WaitForIdle(); + WAIT_FOR(1000, 1000, (RouteFind("vrf1", "11.1.1.200", 32))); + EXPECT_FALSE(RouteFind("vrf1", "224.0.0.0", 8)); + EXPECT_FALSE(RouteFindV6("vrf1", "ff00::", 8)); + EXPECT_TRUE(RouteFind(Agent::GetInstance()->fabric_vrf_name(), + "224.0.0.0", 8)); + EXPECT_TRUE(RouteFindV6(Agent::GetInstance()->fabric_vrf_name(), + "ff00::", 8)); + + //Restore and cleanup + client->Reset(); + DelIPAM("vn1"); + client->WaitForIdle(); + DeleteVmportEnv(input, 1, true); + client->WaitForIdle(); + WAIT_FOR(1000, 1000, (VrfFind("vrf1") == false)); +} + int main(int argc, char **argv) { GETUSERARGS();