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();