diff --git a/mcproxy/include/parser/configuration.hpp b/mcproxy/include/parser/configuration.hpp index 801b7fbb45660ff1723a1a1cca81c5402667c98f..5141ca5d954968e43852d585399c36b5f0ca0e82 100644 --- a/mcproxy/include/parser/configuration.hpp +++ b/mcproxy/include/parser/configuration.hpp @@ -45,7 +45,7 @@ private: int m_qri = -1; // Query response interval int m_lmqi = -1; // Last member Query interval int m_rv = -1; // robustness value - bool m_fastleave = true; // Fast leave + bool m_fastleave = false; // Fast leave //<line number (for a better error message output), command> std::vector<std::pair<unsigned int, std::string>> m_cmds; diff --git a/mcproxy/include/proxy/timers_values.hpp b/mcproxy/include/proxy/timers_values.hpp index 03ba3136f44a32c099d20c31c36318e884180433..808c348f4c532706768ffaa90964d3f158a4afab 100644 --- a/mcproxy/include/proxy/timers_values.hpp +++ b/mcproxy/include/proxy/timers_values.hpp @@ -36,6 +36,7 @@ struct timers_values_tank { std::chrono::milliseconds last_listener_query_interval = std::chrono::milliseconds(1000); unsigned int last_listener_query_count = robustness_variable; std::chrono::milliseconds unsolicited_report_interval = std::chrono::milliseconds(1000); + bool fastleave = false; }; static timers_values_tank default_timers_values_tank = timers_values_tank(); @@ -82,6 +83,7 @@ public: std::chrono::milliseconds get_last_listener_query_time() const; // std::chrono::milliseconds get_unsolicited_report_interval() const; std::chrono::milliseconds get_older_host_present_interval() const; // + bool get_fastleave() const; void set_robustness_variable(unsigned int robustness_variable); void set_query_interval(std::chrono::seconds query_interval); @@ -91,6 +93,7 @@ public: void set_last_listener_query_interval(std::chrono::milliseconds last_listener_query_interval); void set_last_listener_query_count(unsigned int last_listener_query_count); void set_unsolicited_report_interval(std::chrono::milliseconds unsolicited_report_interval); + void set_fastleave(bool fastleave); void reset_to_default_tank(); diff --git a/mcproxy/src/proxy/proxy.cpp b/mcproxy/src/proxy/proxy.cpp index 34b3ee9af85183319f01b3954191d8a17114071f..7f1a446131239e102dbdff2f6645003d103a31c7 100644 --- a/mcproxy/src/proxy/proxy.cpp +++ b/mcproxy/src/proxy/proxy.cpp @@ -276,7 +276,9 @@ void proxy::start_proxy_instances() tv.set_startup_query_count(val); } - std::cout << "fastleave :" <<m_configuration->get_fastleave() <<std::endl; + bool fastleave = m_configuration->get_fastleave(); + std::cout << "fastleave :" <<fastleave <<std::endl; + tv.set_fastleave(fastleave); pr_i->add_msg(std::make_shared<config_msg>(config_msg::ADD_DOWNSTREAM, if_index, d, tv)); } diff --git a/mcproxy/src/proxy/querier.cpp b/mcproxy/src/proxy/querier.cpp index 9e6c32297f7844b62160614822b843e29da9d6a7..c4f8b9e8ab051358bb227b0c109c79b9d516b71f 100644 --- a/mcproxy/src/proxy/querier.cpp +++ b/mcproxy/src/proxy/querier.cpp @@ -35,6 +35,95 @@ #include <iostream> #include <sstream> +extern "C" { + +#include <netinet/ip.h> +#include <linux/if_bridge.h> +#include <asm/types.h> +#include <libnetlink.h> +#include <linux/netlink.h> +#include <linux/rtnetlink.h> + +#ifndef MDBA_RTA +#define MDBA_RTA(r) \ + ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg)))) +#endif + +static unsigned int group_ports = 0; + +static void +check_mdb_entry(struct nlmsghdr *n, struct in_addr *gaddr, struct rtattr *attr) +{ + struct rtattr *i; + struct br_mdb_entry *e; + + int rem = RTA_PAYLOAD(attr); + for (i = (struct rtattr *) RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { + e = (br_mdb_entry*) RTA_DATA(i); + + if (e->addr.proto == htons(ETH_P_IP) && e->addr.u.ip4 == gaddr->s_addr) + group_ports++; + } +} + +static int parse_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) +{ + struct in_addr *gaddr = (struct in_addr *) arg; + struct br_port_msg *r = (struct br_port_msg *) NLMSG_DATA(n); + int len = n->nlmsg_len; + struct rtattr *tb[MDBA_MAX + 1]; + + if (n->nlmsg_type != RTM_GETMDB) + return -1; + + len -= NLMSG_LENGTH(sizeof (*r)); + if (len < 0) { + printf("BUG: wrong nlmsg len %d\n", len); + return -1; + } + + parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof (*r))); + + if (tb[MDBA_MDB]) { + struct rtattr *i; + int rem = RTA_PAYLOAD(tb[MDBA_MDB]); + + for (i = (struct rtattr*) RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) + check_mdb_entry(n, gaddr, i); + } + + return 0; +} + +unsigned int group_mem_port_count(struct in_addr gaddr) +{ + struct rtnl_handle rth; + + group_ports = 0; + + if (rtnl_open(&rth, 0) < 0) { + printf("rtnl_open() failed\n"); + goto out; + } + + if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { + printf("Cannot send RTM_GETMDG dump request\n"); + goto out; + } + + if (rtnl_dump_filter(&rth, parse_mdb, &gaddr) < 0) { + printf("Dump terminated\n"); + goto out; + } + +out: + rtnl_close(&rth); + + return group_ports; +} + +} + querier::querier(worker* msg_worker, group_mem_protocol querier_version_mode, int if_index, const std::shared_ptr<const sender>& sender, const std::shared_ptr<timing>& timing, const timers_values& tv, callback_querier_state_change cb_state_change) : m_msg_worker(msg_worker) , m_if_index(if_index) @@ -163,7 +252,15 @@ void querier::receive_record(const std::shared_ptr<proxy_msg>& msg) break; case EXCLUDE_MODE: - receive_record_in_exclude_mode(gr->get_record_type(), gr->get_gaddr(), gr->get_slist(), db_info_it->second); + if (m_timers_values.get_fastleave() && gr->get_record_type() == CHANGE_TO_INCLUDE_MODE && gr->get_slist().empty()) { + //Only leave the group on upstream, when no any LAN port in the group + if (!group_mem_port_count(gr->get_gaddr().get_in_addr())) { + m_db.group_info.erase(db_info_it); + state_change_notification(gr->get_gaddr()); + } + } else + receive_record_in_exclude_mode(gr->get_record_type(), gr->get_gaddr(), gr->get_slist(), db_info_it->second); + break; default : HC_LOG_ERROR("wrong filter mode: " << db_info_it->second.filter_mode); @@ -778,6 +875,7 @@ void querier::state_change_notification(const addr_storage& gaddr) m_cb_state_change(m_if_index, gaddr); } + querier::~querier() { HC_LOG_TRACE(""); diff --git a/mcproxy/src/proxy/timers_values.cpp b/mcproxy/src/proxy/timers_values.cpp index 164e47a0e98da594e53cf3ef7a15b6c0d61d452f..67959d15ae4ee9f9b931e722c0a2f6c2fcfc61b3 100644 --- a/mcproxy/src/proxy/timers_values.cpp +++ b/mcproxy/src/proxy/timers_values.cpp @@ -176,6 +176,12 @@ uint16_t timers_values::maxrespi_to_maxrespc_mldv2(const std::chrono::millisecon } //-------------------------------------- +bool timers_values::get_fastleave() const +{ + HC_LOG_TRACE(""); + return tank->fastleave; +} + unsigned int timers_values::get_robustness_variable() const { HC_LOG_TRACE(""); @@ -271,6 +277,13 @@ void timers_values::reset_to_default_tank() } //-------------------------------------- +void timers_values::set_fastleave(bool fastleave) +{ + HC_LOG_TRACE(""); + set_new_tank(); + tank->fastleave = fastleave; +} + void timers_values::set_robustness_variable(unsigned int robustness_variable) { HC_LOG_TRACE("");