1 /* 2 * Copyright (c) 2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #include <sys/param.h> 8 #include <sys/module.h> 9 #include <sys/types.h> 10 #include <sys/socket.h> 11 #include <netinet/in.h> 12 #include <arpa/inet.h> 13 #include <net/if_gre.h> 14 15 #include <netlink/netlink.h> 16 #include <netlink/netlink_route.h> 17 #include "netlink/netlink_snl.h" 18 #include <netlink/netlink_snl_route.h> 19 #include <netlink/netlink_snl_route_compat.h> 20 #include <netlink/netlink_snl_route_parsers.h> 21 22 #include <atf-c.h> 23 24 struct nl_parsed_gre { 25 struct sockaddr *ifla_local; 26 struct sockaddr *ifla_remote; 27 uint32_t ifla_flags; 28 uint32_t ifla_okey; 29 uint32_t ifla_encap_type; 30 uint16_t ifla_encap_sport; 31 }; 32 33 struct nla_gre_info { 34 const char *kind; 35 struct nl_parsed_gre data; 36 }; 37 38 struct nla_gre_link { 39 uint32_t ifi_index; 40 struct nla_gre_info linkinfo; 41 }; 42 43 #define _OUT(_field) offsetof(struct nl_parsed_gre, _field) 44 static const struct snl_attr_parser nla_p_gre[] = { 45 { .type = IFLA_GRE_LOCAL, .off = _OUT(ifla_local), .cb = snl_attr_get_ip }, 46 { .type = IFLA_GRE_REMOTE, .off = _OUT(ifla_remote), .cb = snl_attr_get_ip }, 47 { .type = IFLA_GRE_FLAGS, .off = _OUT(ifla_flags), .cb = snl_attr_get_uint32 }, 48 { .type = IFLA_GRE_OKEY, .off = _OUT(ifla_okey), .cb = snl_attr_get_uint32 }, 49 { .type = IFLA_GRE_ENCAP_TYPE, .off = _OUT(ifla_encap_type), .cb = snl_attr_get_uint32 }, 50 { .type = IFLA_GRE_ENCAP_SPORT, .off = _OUT(ifla_encap_sport), .cb = snl_attr_get_uint16 }, 51 }; 52 #undef _OUT 53 SNL_DECLARE_ATTR_PARSER(gre_linkinfo_data_parser, nla_p_gre); 54 55 #define _OUT(_field) offsetof(struct nla_gre_info, _field) 56 static const struct snl_attr_parser ap_gre_linkinfo[] = { 57 { .type = IFLA_INFO_KIND, .off = _OUT(kind), .cb = snl_attr_get_string }, 58 { .type = IFLA_INFO_DATA, .off = _OUT(data), 59 .arg = &gre_linkinfo_data_parser, .cb = snl_attr_get_nested }, 60 }; 61 #undef _OUT 62 SNL_DECLARE_ATTR_PARSER(gre_linkinfo_parser, ap_gre_linkinfo); 63 64 #define _IN(_field) offsetof(struct ifinfomsg, _field) 65 #define _OUT(_field) offsetof(struct nla_gre_link, _field) 66 static const struct snl_attr_parser ap_gre_link[] = { 67 { .type = IFLA_LINKINFO, .off = _OUT(linkinfo), 68 .arg = &gre_linkinfo_parser, .cb = snl_attr_get_nested }, 69 }; 70 71 static const struct snl_field_parser fp_gre_link[] = { 72 { .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 }, 73 }; 74 #undef _IN 75 #undef _OUT 76 SNL_DECLARE_PARSER(gre_parser, struct ifinfomsg, fp_gre_link, ap_gre_link); 77 78 ATF_TC(test_rtnl_gre); 79 ATF_TC_HEAD(test_rtnl_gre, tc) 80 { 81 atf_tc_set_md_var(tc, "descr", "test gre interface using netlink"); 82 atf_tc_set_md_var(tc, "require.user", "root"); 83 atf_tc_set_md_var(tc, "require.kmods", "netlink if_gre"); 84 } 85 86 ATF_TC_BODY(test_rtnl_gre, tc) 87 { 88 struct snl_state ss; 89 struct snl_writer nw; 90 struct nlmsghdr *hdr, *rx_hdr; 91 struct in_addr src, dst; 92 struct nla_gre_link lattrs = {}; 93 struct nl_parsed_gre attrs = {}; 94 struct snl_errmsg_data e = {}; 95 struct ifinfomsg *ifmsg; 96 int off, off2; 97 98 ATF_REQUIRE_MSG(snl_init(&ss, NETLINK_ROUTE), "snl_init() failed"); 99 100 /* Create gre interface */ 101 snl_init_writer(&ss, &nw); 102 ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_NEWLINK)) != NULL); 103 hdr->nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST | NLM_F_ACK); 104 snl_reserve_msg_object(&nw, struct ifinfomsg); 105 106 /* Create parameters */ 107 snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gre10"); 108 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO); 109 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gre"); 110 off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA); 111 112 inet_pton(AF_INET, "127.0.0.1", &src); 113 inet_pton(AF_INET, "127.0.0.2", &dst); 114 snl_add_msg_attr_ip4(&nw, IFLA_GRE_LOCAL, &src); 115 snl_add_msg_attr_ip4(&nw, IFLA_GRE_REMOTE, &dst); 116 snl_add_msg_attr_u32(&nw, IFLA_GRE_FLAGS, (GRE_ENABLE_SEQ | GRE_ENABLE_CSUM)); 117 snl_add_msg_attr_u32(&nw, IFLA_GRE_OKEY, 123456); 118 snl_add_msg_attr_u32(&nw, IFLA_GRE_ENCAP_TYPE, IFLA_TUNNEL_GRE_UDP); 119 snl_add_msg_attr_u16(&nw, IFLA_GRE_ENCAP_SPORT, 50000); 120 121 snl_end_attr_nested(&nw, off2); 122 snl_end_attr_nested(&nw, off); 123 124 ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL); 125 ATF_REQUIRE(snl_send_message(&ss, hdr)); 126 ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL); 127 ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e)); 128 ATF_REQUIRE_INTEQ(e.error, 0); 129 130 /* Dump gre interface */ 131 snl_init_writer(&ss, &nw); 132 ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_GETLINK)) != NULL); 133 hdr->nlmsg_flags |= NLM_F_DUMP; 134 snl_reserve_msg_object(&nw, struct ifinfomsg); 135 snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gre10"); 136 off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO); 137 snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gre"); 138 snl_end_attr_nested(&nw, off); 139 140 ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL); 141 ATF_REQUIRE(snl_send_message(&ss, hdr)); 142 143 /* Check parameters */ 144 ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL); 145 ATF_CHECK(snl_parse_nlmsg(&ss, rx_hdr, &gre_parser, &lattrs)); 146 attrs = lattrs.linkinfo.data; 147 ATF_CHECK_STREQ(lattrs.linkinfo.kind, "gre"); 148 ATF_CHECK_INTEQ(attrs.ifla_flags, (GRE_ENABLE_SEQ | GRE_ENABLE_CSUM | GRE_UDPENCAP)); 149 ATF_CHECK_INTEQ(attrs.ifla_okey, 123456); 150 ATF_CHECK_INTEQ(attrs.ifla_encap_type, IFLA_TUNNEL_GRE_UDP); 151 ATF_CHECK_INTEQ(attrs.ifla_encap_sport, 50000); 152 153 /* Delete gre interface */ 154 snl_init_writer(&ss, &nw); 155 ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_DELLINK)) != NULL); 156 hdr->nlmsg_flags |= (NLM_F_ACK | NLM_F_REQUEST); 157 ATF_REQUIRE((ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg)) != NULL); 158 ifmsg->ifi_index = lattrs.ifi_index; 159 ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL); 160 ATF_REQUIRE(snl_send_message(&ss, hdr)); 161 ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL); 162 ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e)); 163 ATF_REQUIRE_INTEQ(e.error, 0); 164 } 165 166 ATF_TP_ADD_TCS(tp) 167 { 168 ATF_TP_ADD_TC(tp, test_rtnl_gre); 169 170 return (atf_no_error()); 171 } 172 173