Skip to content

Commit

Permalink
Add timer support
Browse files Browse the repository at this point in the history
  • Loading branch information
yaqiangz committed Dec 13, 2024
1 parent cb9fddc commit 79941a5
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 48 deletions.
54 changes: 26 additions & 28 deletions src/config_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries,
std::vector<std::string> servers;
bool option_79_default = true;
bool interface_id_default = false;
const int wait_timeout = 120;
int current_wait = 0;

if (dual_tor_sock) {
interface_id_default = true;
Expand All @@ -128,7 +126,6 @@ void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries,
std::string operation = kfvOp(entry);
std::vector<swss::FieldValueTuple> fieldValues = kfvFieldsValues(entry);
bool has_ipv6_address = false;
bool is_lla_ready = false;

const std::string match_pattern = "VLAN_INTERFACE|" + vlan + "|*";
auto keys = config_db->keys(match_pattern);
Expand All @@ -149,37 +146,13 @@ void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries,
continue;
}

// Checke whether link local address is ready for Vlan, wait total 120s for all Vlans
do {
const std::string cmd = "ip -6 addr show " + vlan + " scope link 2> /dev/null";
std::array<char, 256> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
if (pipe) {
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
if (!result.empty()) {
is_lla_ready = true;
break;
}
}
syslog(LOG_WARNING, "Cannot get link local address for %s, wait 5s", vlan.c_str());
sleep(5);
current_wait += 5;
} while (current_wait <= wait_timeout);

if (!is_lla_ready) {
syslog(LOG_WARNING, "%s doesn't have IPv6 link local address, skip it", vlan.c_str());
continue;
}

relay_config intf;
intf.is_option_79 = option_79_default;
intf.is_interface_id = interface_id_default;
intf.interface = vlan;
intf.mux_key = "";
intf.state_db = nullptr;
intf.is_lla_ready = false;
for (auto &fieldValue: fieldValues) {
std::string f = fvField(fieldValue);
std::string v = fvValue(fieldValue);
Expand Down Expand Up @@ -208,3 +181,28 @@ void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries,
vlans[vlan] = intf;
}
}

/**
* @code bool check_is_lla_ready(std::string vlan)
*
* @brief Check whether link local address appear in vlan interface
*
* @param vlan string of vlan name
*
* @return bool value indicates whether lla ready
*/
bool check_is_lla_ready(std::string vlan) {
const std::string cmd = "ip -6 addr show " + vlan + " scope link 2> /dev/null";
std::array<char, 256> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
if (pipe) {
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
if (!result.empty()) {
return true;
}
}
return false;
}
11 changes: 11 additions & 0 deletions src/config_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,14 @@ void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::un
*/
void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, std::unordered_map<std::string, relay_config> &vlans,
std::shared_ptr<swss::DBConnector> config_db);

/**
* @code bool check_is_lla_ready(std::string vlan)
*
* @brief Check whether link local address appear in vlan interface
*
* @param vlan string of vlan name
*
* @return bool value indicates whether lla ready
*/
bool check_is_lla_ready(std::string vlan);
104 changes: 84 additions & 20 deletions src/relay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,10 @@ void server_callback_dualtor(evutil_socket_t fd, short event, void *arg) {
syslog(LOG_WARNING, "Invalid DHCPv6 header content on loopback socket, packet will be dropped\n");
continue;
}
if (!config->is_lla_ready) {
syslog(LOG_WARNING, "Link local address for %s is not ready, packet will be dropped\n", config->interface.c_str());
continue;
}
auto loopback_str = std::string(loopback);
increase_counter(config->state_db, loopback_str, msg_type);
relay_relay_reply(server_recv_buffer, buffer_sz, config);
Expand Down Expand Up @@ -1278,7 +1282,87 @@ void loop_relay(std::unordered_map<std::string, relay_config> &vlans) {
}
}

struct event *timer_event;
struct timeval tv;
auto timer_args = new std::tuple<
std::unordered_map<std::string, struct relay_config> &,
std::shared_ptr<swss::DBConnector>,
std::shared_ptr<swss::DBConnector>,
std::shared_ptr<swss::Table>,
std::vector<int>,
int,
int,
struct event *
>(vlans, config_db, state_db, mStateDbMuxTablePtr, sockets, lo_sock, lo_sock, nullptr);
timer_event = event_new(base, -1, EV_PERSIST, lla_check_callback, timer_args);
std::get<7>(*timer_args) = timer_event;
evutil_timerclear(&tv);
tv.tv_sec = 5;
event_add(timer_event, &tv);

if(signal_init() == 0 && signal_start() == 0) {
shutdown_relay();
for(std::size_t i = 0; i < sockets.size(); i++) {
close(sockets.at(i));
}
}
}

/**
* @code shutdown_relay();
*
* @brief free signals and terminate threads
*/
void shutdown_relay() {
event_del(ev_sigint);
event_del(ev_sigterm);
event_free(ev_sigint);
event_free(ev_sigterm);
event_base_free(base);
deinitialize_swss();
}

/**
* @code void lla_check_callback(evutil_socket_t fd, short event, void *arg);
*
* @brief callback for libevent timer to check whether lla is ready for vlan
*
* @param fd libevent socket
* @param event libevent triggered event
* @param arg callback argument provided by user
*
* @return none
*/
void lla_check_callback(evutil_socket_t fd, short event, void *arg) {
syslog(LOG_WARNING, "Timer event");
auto args = reinterpret_cast<std::tuple<
std::unordered_map<std::string, struct relay_config> &,
std::shared_ptr<swss::DBConnector>,
std::shared_ptr<swss::DBConnector>,
std::shared_ptr<swss::Table>,
std::vector<int>,
int,
int,
struct event *
> *>(arg);
auto vlans = std::get<0>(*args);
auto config_db = std::get<1>(*args);
auto state_db = std::get<2>(*args);
auto mStateDbMuxTablePtr = std::get<3>(*args);
auto sockets = std::get<4>(*args);
auto lo_sock = std::get<5>(*args);
auto filter = std::get<6>(*args);
auto timer_event = std::get<7>(*args);

for(auto &vlan : vlans) {
if (vlan.second.is_lla_ready) {
continue;
}
if (!check_is_lla_ready(vlan.first)) {
syslog(LOG_WARNING, "Link local address for %s is not ready\n", vlan.first.c_str());
continue;
}
vlan.second.is_lla_ready = true;
int gua_sock = 0;
int lla_sock = 0;
vlan.second.config_db = config_db;
Expand Down Expand Up @@ -1312,25 +1396,5 @@ void loop_relay(std::unordered_map<std::string, relay_config> &vlans) {
exit(EXIT_FAILURE);
}
}

if(signal_init() == 0 && signal_start() == 0) {
shutdown_relay();
for(std::size_t i = 0; i < sockets.size(); i++) {
close(sockets.at(i));
}
}
}

/**
* @code shutdown_relay();
*
* @brief free signals and terminate threads
*/
void shutdown_relay() {
event_del(ev_sigint);
event_del(ev_sigterm);
event_free(ev_sigint);
event_free(ev_sigterm);
event_base_free(base);
deinitialize_swss();
}
13 changes: 13 additions & 0 deletions src/relay.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ struct relay_config {
bool is_interface_id;
std::shared_ptr<swss::Table> mux_table;
std::shared_ptr<swss::DBConnector> config_db;
bool is_lla_ready;
};

/* DHCPv6 messages and options */
Expand Down Expand Up @@ -474,3 +475,15 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config
*/
void server_callback(evutil_socket_t fd, short event, void *arg);

/**
* @code void lla_check_callback(evutil_socket_t fd, short event, void *arg);
*
* @brief callback for libevent timer to check whether lla is ready for vlan
*
* @param fd libevent socket
* @param event libevent triggered event
* @param arg callback argument provided by user
*
* @return none
*/
void lla_check_callback(evutil_socket_t fd, short event, void *arg);
1 change: 1 addition & 0 deletions test/mock_config_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using namespace ::testing;

MOCK_GLOBAL_FUNC0(get_dhcp, void(void));
TEST(configInterface, initialize_swss) {
std::shared_ptr<swss::DBConnector> config_db = std::make_shared<swss::DBConnector> ("CONFIG_DB", 0);
config_db->hset("DHCP_RELAY|Vlan1000", "dhcpv6_servers@", "fc02:2000::1,fc02:2000::2,fc02:2000::3,fc02:2000::4");
Expand Down

0 comments on commit 79941a5

Please sign in to comment.