Skip to content

Commit ab65ded

Browse files
Merge branch 'master' into pr-template-standardization
2 parents 7930fc8 + d7a78ba commit ab65ded

9 files changed

Lines changed: 552 additions & 241 deletions

File tree

dhcp4relay/src/dhcp4_sender.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <arpa/inet.h>
44
#include <errno.h>
5-
#include <syslog.h>
5+
#include "logger.h"
66

77
#include <cstring>
88

@@ -63,14 +63,14 @@ bool send_udp(int sock, uint8_t *buffer, struct sockaddr_in target, uint32_t len
6363
if (sendmsg(sock, &msg, 0) == -1) {
6464
char server_addr[INET_ADDRSTRLEN];
6565
inet_ntop(AF_INET, &(target.sin_addr), server_addr, INET_ADDRSTRLEN);
66-
syslog(LOG_ERR, "sendmsg: Failed to send to target address: %s, error: %s\n", server_addr, strerror(errno));
66+
SWSS_LOG_ERROR("sendmsg: Failed to send to target address: %s, error: %s", server_addr, strerror(errno));
6767
return false;
6868
}
6969
} else {
7070
if (sendto(sock, buffer, len, 0, (const struct sockaddr *)&target, sizeof(target)) == -1) {
7171
char server_addr[INET_ADDRSTRLEN];
7272
inet_ntop(AF_INET, &(target.sin_addr), server_addr, INET_ADDRSTRLEN);
73-
syslog(LOG_ERR, "sendto: Failed to send to target address: %s, error: %s\n", server_addr, strerror(errno));
73+
SWSS_LOG_ERROR("sendto: Failed to send to target address: %s, error: %s", server_addr, strerror(errno));
7474
return false;
7575
}
7676
}

dhcp4relay/src/dhcp4relay.cpp

Lines changed: 268 additions & 181 deletions
Large diffs are not rendered by default.

dhcp4relay/src/dhcp4relay.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include <netinet/if_ether.h>
1010
#include <netinet/ip.h>
1111
#include <netinet/udp.h>
12-
#include <syslog.h>
12+
#include "logger.h"
1313

1414
#include <map>
1515
#include <string>
@@ -27,6 +27,11 @@
2727
#define DHCPv4_OPTION_LIMIT 255
2828
#define RAWSOCKET_RECV_SIZE 1048576
2929
#define CLIENT_IF_PREFIX "Ethernet"
30+
#define VRF_NAME_FIELD "vrf_name" // typo "vrf" caused VRF-update miss; field is "vrf_name"
31+
#define SERVER_VRF_FIELD "server_vrf"
32+
#define SOURCE_INTERFACE_FIELD "source_interface"
33+
#define LINK_SELECTION_FIELD "link_selection"
34+
#define STATE_FIELD "state"
3035
#define BUFFER_SIZE 9200 // TODO: change to dynamic size based on MTU
3136
#define MAX_DHCP_PKT_SIZE 1472 // 1500 - (IP + UDP)headers
3237
#define MAC_ADDR_STR_LEN 17
@@ -104,7 +109,6 @@ struct relay_config {
104109
sockaddr_in link_address_netmask;
105110
sockaddr_in src_intf_sel_addr;
106111
uint32_t link_ifindex;
107-
std::shared_ptr<swss::DBConnector> state_db;
108112
std::string vlan;
109113
std::string phy_interface;
110114
std::string vrf; // This is server VRF.
@@ -118,7 +122,6 @@ struct relay_config {
118122
std::vector<sockaddr_in> servers_sock;
119123
bool is_interface_id;
120124
bool is_add;
121-
std::shared_ptr<swss::DBConnector> config_db;
122125
};
123126

124127
typedef enum {
@@ -132,7 +135,16 @@ typedef enum {
132135
DHCPv4_SERVER_IP_UPDATE,
133136
DHCPv4_SERVER_IP_DELETE,
134137
DHCPv4_RELAY_DUAL_TOR_UPDATE,
135-
DHCPv4_RELAY_PORT_UPDATE
138+
DHCPv4_RELAY_PORT_UPDATE,
139+
/*
140+
* General-purpose main<->mgr synchronisation barrier on
141+
* config_pipe. The mgr thread emits one to mark a coherent
142+
* point in the event stream; the main thread blocks until it
143+
* consumes one. Currently used to gate pkt_in_callback on the
144+
* initial DHCPV4_RELAY snapshot. Reusable for Redis-reconnect
145+
* resync, atomic config replace, etc.
146+
*/
147+
DHCPv4_RELAY_SYNC_BARRIER
136148
} event_type;
137149

138150
struct event_config {

dhcp4relay/src/dhcp4relay_mgr.cpp

Lines changed: 86 additions & 43 deletions
Large diffs are not rendered by default.

dhcp4relay/src/dhcp4relay_stats.cpp

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,12 @@ void update_interface_counters_in_db(
7373

7474
// Populate existing counters
7575
for (const auto& field : existing_fields) {
76-
counter_map[fvField(field)] = std::stoi(fvValue(field));
76+
try {
77+
counter_map[fvField(field)] = std::stoi(fvValue(field));
78+
} catch (const std::exception &e) {
79+
SWSS_LOG_WARN("[DHCPV4_RELAY] update_interface_counters_in_db: invalid counter value '%s' for field '%s': %s",
80+
fvValue(field).c_str(), fvField(field).c_str(), e.what());
81+
}
7782
}
7883

7984
// Update with new values
@@ -135,7 +140,7 @@ void DHCPCounter_table::db_update_loop() {
135140
}
136141
}
137142
}
138-
syslog(LOG_INFO, "DHCPV4_RELAY: DHCPCounter_table::db_update_loop() : Data Updated to DB \n");
143+
SWSS_LOG_INFO("DHCPV4_RELAY: DHCPCounter_table::db_update_loop() : Data Updated to DB ");
139144
}
140145
}
141146

@@ -198,13 +203,27 @@ void DHCPCounter_table::initialize_interface(const std::string& interface) {
198203
void DHCPCounter_table::increment_counter(const std::string& interface,
199204
const std::string& direction,
200205
int msg_type) {
201-
std::string type = counter_map.find(msg_type)->second;
202-
// Initialize counters if not present
203-
if (interfaces_cntr_table.find(interface) == interfaces_cntr_table.end())
204-
DHCPCounter_table::initialize_interface(interface);
206+
auto type_itr = counter_map.find(msg_type);
207+
if (type_itr == counter_map.end()) {
208+
SWSS_LOG_WARN("[DHCPV4_RELAY] increment_counter: unknown msg_type %d, counting as Unknown", msg_type);
209+
type_itr = counter_map.find(DHCPv4_MESSAGE_TYPE_UNKNOWN);
210+
if (type_itr == counter_map.end()) {
211+
return;
212+
}
213+
}
214+
const std::string &type = type_itr->second;
205215

206216
std::lock_guard<std::mutex> lock(interfaces_mutex);
207217

218+
if (interfaces_cntr_table.find(interface) == interfaces_cntr_table.end()) {
219+
DHCPCounters counter;
220+
for (const auto& t : counter_map) {
221+
counter.RX[t.second] = 0;
222+
counter.TX[t.second] = 0;
223+
}
224+
interfaces_cntr_table[interface] = counter;
225+
}
226+
208227
if (direction == "RX") {
209228
interfaces_cntr_table[interface].RX[type]++;
210229
} else if (direction == "TX") {

dhcp4relay/src/main.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <stdlib.h>
2-
#include <syslog.h>
2+
#include "logger.h"
33

44
#include <unordered_map>
55

@@ -9,11 +9,12 @@ bool dual_tor_sock = false;
99
char loopback[IF_NAMESIZE] = "Loopback0";
1010

1111
int main(int argc, char *argv[]) {
12+
swss::Logger::linkToDbNative("dhcp4relay");
1213
try {
1314
std::unordered_map<std::string, relay_config> vlans;
1415
loop_relay(vlans);
1516
} catch (std::exception &e) {
16-
syslog(LOG_ERR, "An exception occurred.\n");
17+
SWSS_LOG_ERROR("An exception occurred.");
1718
return 1;
1819
}
1920
return 0;

dhcp4relay/test/mock_relay.cpp

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,8 +333,11 @@ TEST(relayConfig, handle_interface_events) {
333333
.Times(AtLeast(1))
334334
.WillRepeatedly(Invoke(RealWrite));
335335
ASSERT_NE(pipe(pipe_fds), -1);
336-
relay_config *config = new relay_config();
336+
337337
std::unordered_map<std::string, relay_config> vlans;
338+
vlans["Vlan100"].vlan = "Vlan100";
339+
340+
relay_config *config = new relay_config();
338341
config->vlan = "Vlan100";
339342
config->is_add = true;
340343
config->src_intf_sel_addr.sin_family = AF_INET;
@@ -370,8 +373,41 @@ TEST(relayConfig, handle_interface_events) {
370373
close(pipe_fds[1]);
371374
}
372375

376+
TEST(relayConfig, handle_interface_events_unknown_vlan) {
377+
int pipe_fds[2];
378+
EXPECT_GLOBAL_CALL(write, write(_, _, _))
379+
.Times(AtLeast(1))
380+
.WillRepeatedly(Invoke(RealWrite));
381+
ASSERT_NE(pipe(pipe_fds), -1);
382+
383+
std::unordered_map<std::string, relay_config> vlans;
384+
385+
relay_config *config = new relay_config();
386+
config->vlan = "Vlan999";
387+
config->is_add = true;
388+
config->src_intf_sel_addr.sin_family = AF_INET;
389+
config->src_intf_sel_addr.sin_addr.s_addr = inet_addr("10.0.0.1");
390+
391+
event_config event;
392+
event.type = DHCPv4_RELAY_INTERFACE_UPDATE;
393+
event.msg = static_cast<void *>(config);
394+
395+
ASSERT_NE(write(pipe_fds[1], &event, sizeof(event)), -1);
396+
397+
config_event_callback(pipe_fds[0], 0, &vlans);
398+
399+
EXPECT_TRUE(vlans.find("Vlan999") == vlans.end());
400+
401+
close(pipe_fds[0]);
402+
close(pipe_fds[1]);
403+
}
404+
373405
TEST(relayConfig, handle_vlan_member_events) {
406+
struct ifaddrs *mock_ifaddrs = CreateMockIfaddrs("192.168.1.1", "255.255.255.0", "Vlan100", "192.168.1.2", "Ethernet4");
374407
int pipe_fds[2];
408+
EXPECT_GLOBAL_CALL(getifaddrs, getifaddrs(_))
409+
.WillRepeatedly(DoAll(testing::SetArgPointee<0>(mock_ifaddrs), Return(0)));
410+
EXPECT_GLOBAL_CALL(freeifaddrs, freeifaddrs(_)).Times(AtLeast(2));
375411
EXPECT_GLOBAL_CALL(write, write(_, _, _))
376412
.Times(AtLeast(1))
377413
.WillRepeatedly(Invoke(RealWrite));
@@ -417,6 +453,7 @@ TEST(relayConfig, handle_vlan_member_events) {
417453

418454
close(pipe_fds[0]);
419455
close(pipe_fds[1]);
456+
FreeMockIfaddrs(mock_ifaddrs);
420457
}
421458

422459
TEST(relayConfig, handle_vlan_interface_events) {
@@ -937,3 +974,100 @@ TEST(DHCPRelayTest, from_client) {
937974
});
938975
from_client(&dhcpLayer, config);
939976
}
977+
978+
/* Helper: build a relay-of-relay packet (giaddr already set) with a pre-existing Option 82. */
979+
static relay_config make_relay_of_relay_config(const std::string &agent_relay_mode) {
980+
interface_list.push_back("Ethernet12");
981+
phy_interface_alias_map["Ethernet12"] = "eth12";
982+
983+
relay_config config = {};
984+
config.phy_interface = "Ethernet12";
985+
config.vlan = "Vlan10";
986+
config.agent_relay_mode = agent_relay_mode;
987+
config.max_hop_count = 16;
988+
struct sockaddr_in addr = {0};
989+
addr.sin_family = AF_INET;
990+
addr.sin_addr.s_addr = inet_addr("192.168.20.100");
991+
config.servers_sock = {addr};
992+
config.servers = {"192.168.20.100"};
993+
config.link_address.sin_addr.s_addr = inet_addr("192.168.10.10");
994+
config.link_address_netmask.sin_addr.s_addr = inet_addr("255.255.255.0");
995+
vlan_vrf_map["Vlan10"] = "Vrf01";
996+
m_config.host_mac_addr = "12:32:54:24:95:36";
997+
return config;
998+
}
999+
1000+
/* agent_relay_mode=append: packet already has Option 82; we should append ours and forward. */
1001+
TEST(DHCPRelayTest, from_client_relay_of_relay_append) {
1002+
relay_config config = make_relay_of_relay_config("append");
1003+
1004+
pcpp::MacAddress clientMac(std::string("00:0e:86:11:c0:75"));
1005+
pcpp::DhcpLayer dhcpLayer(pcpp::DHCP_DISCOVER, clientMac);
1006+
dhcpLayer.getDhcpHeader()->hops = 0;
1007+
/* Non-zero giaddr signals relay-of-relay path */
1008+
dhcpLayer.getDhcpHeader()->gatewayIpAddress = inet_addr("192.168.1.1");
1009+
encode_relay_option(&dhcpLayer, &config);
1010+
1011+
EXPECT_GLOBAL_CALL(send_udp, send_udp(_, _, _, _, _, _, _)).WillOnce([]
1012+
(int, uint8_t* hdr, struct sockaddr_in, uint32_t, in_addr, bool, bool) {
1013+
pcpp::dhcp_header* dhcp_hdr = (pcpp::dhcp_header*)hdr;
1014+
EXPECT_EQ(dhcp_hdr->hops, 1);
1015+
EXPECT_EQ(dhcp_hdr->gatewayIpAddress, inet_addr("192.168.1.1"));
1016+
return true;
1017+
});
1018+
from_client(&dhcpLayer, config);
1019+
}
1020+
1021+
/* agent_relay_mode=replace: existing Option 82 stripped, ours added, packet forwarded. */
1022+
TEST(DHCPRelayTest, from_client_relay_of_relay_replace) {
1023+
relay_config config = make_relay_of_relay_config("replace");
1024+
1025+
pcpp::MacAddress clientMac(std::string("00:0e:86:11:c0:75"));
1026+
pcpp::DhcpLayer dhcpLayer(pcpp::DHCP_DISCOVER, clientMac);
1027+
dhcpLayer.getDhcpHeader()->hops = 0;
1028+
dhcpLayer.getDhcpHeader()->gatewayIpAddress = inet_addr("192.168.1.1");
1029+
encode_relay_option(&dhcpLayer, &config);
1030+
1031+
EXPECT_GLOBAL_CALL(send_udp, send_udp(_, _, _, _, _, _, _)).WillOnce([]
1032+
(int, uint8_t* hdr, struct sockaddr_in, uint32_t, in_addr, bool, bool) {
1033+
pcpp::dhcp_header* dhcp_hdr = (pcpp::dhcp_header*)hdr;
1034+
EXPECT_EQ(dhcp_hdr->hops, 1);
1035+
EXPECT_EQ(dhcp_hdr->gatewayIpAddress, inet_addr("192.168.1.1"));
1036+
return true;
1037+
});
1038+
from_client(&dhcpLayer, config);
1039+
}
1040+
1041+
/* agent_relay_mode=forward: packet forwarded unchanged, Option 82 not modified. */
1042+
TEST(DHCPRelayTest, from_client_relay_of_relay_forward) {
1043+
relay_config config = make_relay_of_relay_config("forward");
1044+
1045+
pcpp::MacAddress clientMac(std::string("00:0e:86:11:c0:75"));
1046+
pcpp::DhcpLayer dhcpLayer(pcpp::DHCP_DISCOVER, clientMac);
1047+
dhcpLayer.getDhcpHeader()->hops = 0;
1048+
dhcpLayer.getDhcpHeader()->gatewayIpAddress = inet_addr("192.168.1.1");
1049+
encode_relay_option(&dhcpLayer, &config);
1050+
1051+
EXPECT_GLOBAL_CALL(send_udp, send_udp(_, _, _, _, _, _, _)).WillOnce([]
1052+
(int, uint8_t* hdr, struct sockaddr_in, uint32_t, in_addr, bool, bool) {
1053+
pcpp::dhcp_header* dhcp_hdr = (pcpp::dhcp_header*)hdr;
1054+
EXPECT_EQ(dhcp_hdr->hops, 1);
1055+
EXPECT_EQ(dhcp_hdr->gatewayIpAddress, inet_addr("192.168.1.1"));
1056+
return true;
1057+
});
1058+
from_client(&dhcpLayer, config);
1059+
}
1060+
1061+
/* agent_relay_mode=discard: packet must be dropped, send_udp must NOT be called. */
1062+
TEST(DHCPRelayTest, from_client_relay_of_relay_discard) {
1063+
relay_config config = make_relay_of_relay_config("discard");
1064+
1065+
pcpp::MacAddress clientMac(std::string("00:0e:86:11:c0:75"));
1066+
pcpp::DhcpLayer dhcpLayer(pcpp::DHCP_DISCOVER, clientMac);
1067+
dhcpLayer.getDhcpHeader()->hops = 0;
1068+
dhcpLayer.getDhcpHeader()->gatewayIpAddress = inet_addr("192.168.1.1");
1069+
encode_relay_option(&dhcpLayer, &config);
1070+
1071+
EXPECT_GLOBAL_CALL(send_udp, send_udp(_, _, _, _, _, _, _)).Times(0);
1072+
from_client(&dhcpLayer, config);
1073+
}

dhcp6relay/src/relay.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,7 +947,7 @@ void client_packet_handler(uint8_t *buffer, ssize_t length, struct relay_config
947947
const struct ip6_ext *ext_header;
948948
do {
949949
ext_header = (const struct ip6_ext *)current_position;
950-
current_position += ext_header->ip6e_len;
950+
current_position += (ext_header->ip6e_len + 1) * 8;
951951
if((current_position == prev) ||
952952
(current_position + sizeof(*ext_header) >= buffer_end)) {
953953
return;

dhcp6relay/test/mock_relay.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,18 @@ TEST(relay, client_packet_handler) {
721721
0x00, 0x00, 0x00, 0x19, 0x00, 0x0c, 0x27, 0xfe, 0x8f, 0x95, 0x00, 0x00, 0x0e, 0x10, 0x00, 0x00,
722722
0x15, 0x18
723723
};
724+
// Packet with Hop-by-Hop extension header (ip6e_len=1 => 16 bytes per RFC 2460: (1+1)*8=16).
725+
// Tests that the extension header pointer arithmetic is correct for nonzero ip6e_len.
726+
// IPv6 next_header=0x00 (HbH), ext: nxt=0x11(UDP), len=0x01 -> advance 16 bytes -> UDP dst=547
727+
uint8_t client_raw_solicit_with_hbh_extension[] = {
728+
0x33, 0x33, 0x00, 0x01, 0x00, 0x02, 0x08, 0x00, 0x27, 0xfe, 0x8f, 0x95, 0x86, 0xdd, 0x60, 0x00,
729+
0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
730+
0x27, 0xff, 0xfe, 0xfe, 0x8f, 0x95, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
731+
0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
732+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x22, 0x02, 0x23, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x10,
733+
0x08, 0x74
734+
};
735+
724736
uint8_t non_udp_with_externsion[] = {
725737
0x33, 0x33, 0x00, 0x01, 0x00, 0x02, 0x08, 0x00, 0x27, 0xfe, 0x8f, 0x95, 0x86, 0xdd, 0x60, 0x00,
726738
0x00, 0x00, 0x00, 0x44, 0x2c, 0x01, 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00,
@@ -745,6 +757,9 @@ TEST(relay, client_packet_handler) {
745757
ASSERT_NO_THROW(client_packet_handler(client_raw_solicit_with_externsion, sizeof(client_raw_solicit_with_externsion), &config, ifname));
746758

747759
ASSERT_NO_THROW(client_packet_handler(non_udp_with_externsion, sizeof(non_udp_with_externsion), &config, ifname));
760+
761+
// nonzero ip6e_len=1: must advance (1+1)*8=16 bytes per RFC 2460, not 1 byte
762+
ASSERT_NO_THROW(client_packet_handler(client_raw_solicit_with_hbh_extension, sizeof(client_raw_solicit_with_hbh_extension), &config, ifname));
748763
}
749764

750765
MOCK_GLOBAL_FUNC6(recvfrom, ssize_t(int, void *, size_t, int, struct sockaddr *, socklen_t *));

0 commit comments

Comments
 (0)