@@ -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+
373405TEST (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
422459TEST (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+ }
0 commit comments