Page MenuHomeFreeBSD

D57666.id181565.diff
No OneTemporary

D57666.id181565.diff

diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -90,6 +90,12 @@
#include <net/if_bridgevar.h>
#include <net/if_gif.h>
+#include <netlink/netlink.h>
+#include <netlink/netlink_ctl.h>
+#include <netlink/netlink_var.h>
+#include <netlink/netlink_route.h>
+#include <netlink/route/route_var.h>
+
#include <security/mac/mac_framework.h>
static const char gifname[] = "gif";
@@ -97,6 +103,7 @@
MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface");
static struct sx gif_ioctl_sx;
SX_SYSINIT(gif_ioctl_sx, &gif_ioctl_sx, "gif_ioctl");
+#define GIF_LOCK_ASSERT() sx_assert(&gif_ioctl_sx, SA_XLOCKED);
void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af);
void (*ng_gif_input_orphan_p)(struct ifnet *ifp, struct mbuf *m, int af);
@@ -110,8 +117,18 @@
static int gif_ioctl(struct ifnet *, u_long, caddr_t);
static int gif_transmit(struct ifnet *, struct mbuf *);
static void gif_qflush(struct ifnet *);
-static int gif_clone_create(struct if_clone *, int, caddr_t);
-static void gif_clone_destroy(struct ifnet *);
+static int gif_clone_create(struct if_clone *, char *, size_t,
+ struct ifc_data *, struct ifnet **);
+static int gif_clone_destroy(struct if_clone *, struct ifnet *, uint32_t);
+static int gif_clone_create_nl(struct if_clone *, char *, size_t,
+ struct ifc_data_nl *);
+static int gif_clone_modify_nl(struct ifnet *, struct ifc_data_nl *);
+static void gif_clone_dump_nl(struct ifnet *, struct nl_writer *);
+
+static int gif_set_addr_nl(struct gif_softc *, struct nl_pstate *,
+ struct sockaddr *, struct sockaddr *);
+static int gif_set_flags_nl(struct gif_softc *, struct nl_pstate *,
+ uint32_t);
VNET_DEFINE_STATIC(struct if_clone *, gif_cloner);
#define V_gif_cloner VNET(gif_cloner)
@@ -134,8 +151,145 @@
SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(max_gif_nesting), 0, "Max nested tunnels");
+struct nl_parsed_gif {
+ struct sockaddr *ifla_local;
+ struct sockaddr *ifla_remote;
+ uint32_t ifla_flags;
+};
+
+#define _OUT(_field) offsetof(struct nl_parsed_gif, _field)
+static const struct nlattr_parser nla_p_gif[] = {
+ { .type = IFLA_IPTUN_LOCAL, .off = _OUT(ifla_local), .cb = nlattr_get_ip },
+ { .type = IFLA_IPTUN_REMOTE, .off = _OUT(ifla_remote), .cb = nlattr_get_ip },
+ { .type = IFLA_IPTUN_FLAGS, .off = _OUT(ifla_flags), .cb = nlattr_get_uint32 },
+};
+#undef _OUT
+NL_DECLARE_ATTR_PARSER(gif_modify_parser, nla_p_gif);
+
+static const struct nlhdr_parser *all_parsers[] = {
+ &gif_modify_parser,
+};
+
+static int
+gif_clone_create_nl(struct if_clone *ifc, char *name, size_t len,
+ struct ifc_data_nl *ifd)
+{
+ struct ifc_data ifd_new = {
+ .flags = IFC_F_SYSSPACE,
+ .unit = ifd->unit,
+ };
+
+ return (gif_clone_create(ifc, name, len, &ifd_new, &ifd->ifp));
+}
+
+static int
+gif_clone_modify_nl(struct ifnet *ifp, struct ifc_data_nl *ifd)
+{
+ struct gif_softc *sc;
+ struct nl_parsed_link *lattrs = ifd->lattrs;
+ struct nl_pstate *npt = ifd->npt;
+ struct nl_parsed_gif params = {};
+ struct nlattr *attrs = lattrs->ifla_idata;
+ struct nlattr_bmask bm;
+ int error;
+
+ if ((attrs == NULL) ||
+ (nl_has_attr(ifd->bm, IFLA_LINKINFO) == 0)) {
+ error = nl_modify_ifp_generic(ifp, lattrs, ifd->bm, npt);
+ return (error);
+ }
+
+ error = priv_check(curthread, PRIV_NET_GIF);
+ if (error)
+ return (error);
+
+ nl_get_attrs_bmask_raw(NLA_DATA(attrs), NLA_DATA_LEN(attrs), &bm);
+ if ((error = nl_parse_nested(attrs, &gif_modify_parser, npt, &params)) != 0)
+ return (error);
+
+ sx_xlock(&gif_ioctl_sx);
+ sc = ifp->if_softc;
+ if (sc == NULL)
+ goto generic;
+
+ if (nl_has_attr(&bm, IFLA_IPTUN_LOCAL) && nl_has_attr(&bm, IFLA_IPTUN_REMOTE))
+ error = gif_set_addr_nl(sc, npt, params.ifla_local, params.ifla_remote);
+ else if (nl_has_attr(&bm, IFLA_IPTUN_LOCAL) || nl_has_attr(&bm, IFLA_IPTUN_REMOTE)) {
+ error = EINVAL;
+ nlmsg_report_err_msg(npt, "Specify both remote and local address together");
+ }
+
+ if (error == 0 && nl_has_attr(&bm, IFLA_IPTUN_FLAGS))
+ error = gif_set_flags_nl(sc, npt, params.ifla_flags);
+
+generic:
+ sx_xunlock(&gif_ioctl_sx);
+
+ if (error == 0)
+ error = nl_modify_ifp_generic(ifp, ifd->lattrs, ifd->bm, ifd->npt);
+
+ return (error);
+}
+
+static void
+gif_clone_dump_nl(struct ifnet *ifp, struct nl_writer *nw)
+{
+ struct gif_softc *sc;
+ int off, off2;
+
+ nlattr_add_u32(nw, IFLA_LINK, ifp->if_index);
+ nlattr_add_string(nw, IFLA_IFNAME, ifp->if_xname);
+
+ off = nlattr_add_nested(nw, IFLA_LINKINFO);
+ if (off == 0)
+ return;
+
+ nlattr_add_string(nw, IFLA_INFO_KIND, gifname);
+ off2 = nlattr_add_nested(nw, IFLA_INFO_DATA);
+ if (off2 == 0) {
+ nlattr_set_len(nw, off);
+ return;
+ }
+
+ sx_slock(&gif_ioctl_sx);
+ sc = ifp->if_softc;
+ if (sc == NULL)
+ goto ret;
+
+ if (sc->gif_family == AF_INET) {
+#ifdef INET
+ struct in_aliasreq in;
+ if (in_gif_ioctl(sc, SIOCGIFPSRCADDR, (caddr_t)&in) == 0)
+ nlattr_add_in_addr(nw, IFLA_IPTUN_LOCAL,
+ &in.ifra_addr.sin_addr);
+ if (in_gif_ioctl(sc, SIOCGIFPDSTADDR, (caddr_t)&in) == 0)
+ nlattr_add_in_addr(nw, IFLA_IPTUN_REMOTE,
+ &in.ifra_addr.sin_addr);
+#endif
+ } else if (sc->gif_family == AF_INET6) {
+#ifdef INET6
+ struct in6_aliasreq in6;
+ if (in6_gif_ioctl(sc, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6) == 0)
+ nlattr_add_in6_addr(nw, IFLA_IPTUN_LOCAL,
+ &in6.ifra_addr.sin6_addr);
+ if (in6_gif_ioctl(sc, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6) == 0)
+ nlattr_add_in6_addr(nw, IFLA_IPTUN_REMOTE,
+ &in6.ifra_addr.sin6_addr);
+#endif
+ }
+
+ nlattr_add_u32(nw, IFLA_IPTUN_FLAGS, sc->gif_options);
+
+ret:
+ nlattr_set_len(nw, off2);
+ nlattr_set_len(nw, off);
+
+ sx_sunlock(&gif_ioctl_sx);
+}
+
static int
-gif_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+gif_clone_create(struct if_clone *ifc, char *name, size_t len,
+ struct ifc_data *ifd, struct ifnet **ifpp)
{
struct gif_softc *sc;
@@ -143,7 +297,7 @@
sc->gif_fibnum = curthread->td_proc->p_fibnum;
GIF2IFP(sc) = if_alloc(IFT_GIF);
GIF2IFP(sc)->if_softc = sc;
- if_initname(GIF2IFP(sc), gifname, unit);
+ if_initname(GIF2IFP(sc), gifname, ifd->unit);
GIF2IFP(sc)->if_addrlen = 0;
GIF2IFP(sc)->if_mtu = GIF_MTU;
@@ -161,6 +315,7 @@
bpfattach(GIF2IFP(sc), DLT_NULL, sizeof(u_int32_t));
if (ng_gif_attach_p != NULL)
(*ng_gif_attach_p)(GIF2IFP(sc));
+ *ifpp = GIF2IFP(sc);
return (0);
}
@@ -177,35 +332,49 @@
if (sc != NULL)
gif_delete_tunnel(sc);
sx_xunlock(&gif_ioctl_sx);
+ if_link_state_change(ifp, LINK_STATE_DOWN);
}
#endif /* VIMAGE */
-static void
-gif_clone_destroy(struct ifnet *ifp)
+static int
+gif_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags)
{
struct gif_softc *sc;
sx_xlock(&gif_ioctl_sx);
sc = ifp->if_softc;
gif_delete_tunnel(sc);
+ ifp->if_softc = NULL;
+ /* Allow other threads to read, (e.g. dump_nl) */
+ sx_downgrade(&gif_ioctl_sx);
+ if_link_state_change(GIF2IFP(sc), LINK_STATE_DOWN);
if (ng_gif_detach_p != NULL)
(*ng_gif_detach_p)(ifp);
bpfdetach(ifp);
if_detach(ifp);
- ifp->if_softc = NULL;
- sx_xunlock(&gif_ioctl_sx);
+ sx_sunlock(&gif_ioctl_sx);
GIF_WAIT();
if_free(ifp);
free(sc, M_GIF);
+
+ return (0);
}
static void
vnet_gif_init(const void *unused __unused)
{
-
- V_gif_cloner = if_clone_simple(gifname, gif_clone_create,
- gif_clone_destroy, 0);
+ struct if_clone_addreq_v2 req = {
+ .version = 2,
+ .flags = IFC_F_AUTOUNIT,
+ .match_f = NULL,
+ .create_f = gif_clone_create,
+ .destroy_f = gif_clone_destroy,
+ .create_nl_f = gif_clone_create_nl,
+ .modify_nl_f = gif_clone_modify_nl,
+ .dump_nl_f = gif_clone_dump_nl,
+ };
+ V_gif_cloner = ifc_attach_cloner(gifname, (struct if_clone_addreq *)&req);
#ifdef INET
in_gif_init();
#endif
@@ -220,7 +389,7 @@
vnet_gif_uninit(const void *unused __unused)
{
- if_clone_detach(V_gif_cloner);
+ ifc_detach_cloner(V_gif_cloner);
#ifdef INET
in_gif_uninit();
#endif
@@ -237,6 +406,8 @@
switch (type) {
case MOD_LOAD:
+ NL_VERIFY_PARSERS(all_parsers);
+ break;
case MOD_UNLOAD:
break;
default:
@@ -566,6 +737,37 @@
if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
}
+static int
+gif_set_flags(struct gif_softc *sc, u_int opt)
+{
+ int error = 0;
+
+ GIF_LOCK_ASSERT();
+
+ if (opt & ~GIF_OPTMASK)
+ return (EINVAL);
+ if (sc->gif_options == opt)
+ return (0);
+
+ switch (sc->gif_family) {
+#ifdef INET
+ case AF_INET:
+ error = in_gif_setopts(sc, opt);
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ error = in6_gif_setopts(sc, opt);
+ break;
+#endif
+ default:
+ /* No need to invoke AF-handler */
+ sc->gif_options = opt;
+ }
+
+ return (error);
+}
+
static int
gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -640,27 +842,7 @@
sizeof(options));
if (error)
break;
- if (options & ~GIF_OPTMASK) {
- error = EINVAL;
- break;
- }
- if (sc->gif_options != options) {
- switch (sc->gif_family) {
-#ifdef INET
- case AF_INET:
- error = in_gif_setopts(sc, options);
- break;
-#endif
-#ifdef INET6
- case AF_INET6:
- error = in6_gif_setopts(sc, options);
- break;
-#endif
- default:
- /* No need to invoke AF-handler */
- sc->gif_options = options;
- }
- }
+ error = gif_set_flags(sc, options);
break;
default:
error = EINVAL;
@@ -687,7 +869,7 @@
gif_delete_tunnel(struct gif_softc *sc)
{
- sx_assert(&gif_ioctl_sx, SA_XLOCKED);
+ GIF_LOCK_ASSERT();
if (sc->gif_family != 0) {
CK_LIST_REMOVE(sc, srchash);
CK_LIST_REMOVE(sc, chain);
@@ -697,5 +879,62 @@
}
sc->gif_family = 0;
GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
- if_link_state_change(GIF2IFP(sc), LINK_STATE_DOWN);
+}
+
+static int
+gif_set_addr_nl(struct gif_softc *sc, struct nl_pstate *npt,
+ struct sockaddr *src, struct sockaddr *dst)
+{
+#if defined(INET) || defined(INET6)
+ union {
+#ifdef INET
+ struct in_aliasreq in;
+#endif
+#ifdef INET6
+ struct in6_aliasreq in6;
+#endif
+ } aliasreq;
+#endif
+ int error;
+
+ /* XXX: this sanity check runs again in in[6]_gif_ioctl */
+ if (src->sa_family != dst->sa_family)
+ error = EADDRNOTAVAIL;
+#ifdef INET
+ else if (src->sa_family == AF_INET) {
+ memcpy(&aliasreq.in.ifra_addr, src, sizeof(struct sockaddr_in));
+ memcpy(&aliasreq.in.ifra_dstaddr, dst, sizeof(struct sockaddr_in));
+ error = in_gif_ioctl(sc, SIOCSIFPHYADDR, (caddr_t)&aliasreq.in);
+ }
+#endif
+#ifdef INET6
+ else if (src->sa_family == AF_INET6) {
+ memcpy(&aliasreq.in6.ifra_addr, src, sizeof(struct sockaddr_in6));
+ memcpy(&aliasreq.in6.ifra_dstaddr, dst, sizeof(struct sockaddr_in6));
+ error = in6_gif_ioctl(sc, SIOCSIFPHYADDR_IN6, (caddr_t)&aliasreq.in6);
+ }
+#endif
+ else
+ error = EAFNOSUPPORT;
+
+ if (error == EADDRNOTAVAIL)
+ nlmsg_report_err_msg(npt, "address is invalid");
+ if (error == EEXIST)
+ nlmsg_report_err_msg(npt, "remote and local addresses are the same");
+ if (error == EAFNOSUPPORT)
+ nlmsg_report_err_msg(npt, "address family is not supported");
+
+ return (error);
+}
+
+static int
+gif_set_flags_nl(struct gif_softc *sc, struct nl_pstate *npt, uint32_t opt)
+{
+ int error;
+
+ error = gif_set_flags(sc, opt);
+ if (error == EINVAL)
+ nlmsg_report_err_msg(npt, "gif flags are invalid");
+
+ return (error);
}
diff --git a/sys/netlink/route/interface.h b/sys/netlink/route/interface.h
--- a/sys/netlink/route/interface.h
+++ b/sys/netlink/route/interface.h
@@ -272,6 +272,16 @@
uint32_t mask;
};
+/* IFLA_INFO_DATA gif attributes */
+enum {
+ IFLA_IPTUN_UNSPEC,
+ IFLA_IPTUN_LOCAL,
+ IFLA_IPTUN_REMOTE,
+ IFLA_IPTUN_FLAGS,
+ __IFLA_IPTUN_MAX,
+};
+#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
+
/* IFLA_INFO_DATA gre attributes */
enum {
IFLA_GRE_UNSPEC,
diff --git a/tests/sys/netlink/Makefile b/tests/sys/netlink/Makefile
--- a/tests/sys/netlink/Makefile
+++ b/tests/sys/netlink/Makefile
@@ -6,6 +6,7 @@
ATF_TESTS_C+= netlink_socket
ATF_TESTS_C+= test_snl test_snl_generic
ATF_TESTS_C+= test_rtnl_gre
+ATF_TESTS_C+= test_rtnl_gif
ATF_TESTS_C+= test_rtnl_route
ATF_TESTS_PYTEST += test_nl_core.py
ATF_TESTS_PYTEST += test_rtnl_iface.py
diff --git a/tests/sys/netlink/test_rtnl_gif.c b/tests/sys/netlink/test_rtnl_gif.c
new file mode 100644
--- /dev/null
+++ b/tests/sys/netlink/test_rtnl_gif.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2026 Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if_gif.h>
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_route.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/netlink_snl_route.h>
+#include <netlink/netlink_snl_route_compat.h>
+#include <netlink/netlink_snl_route_parsers.h>
+
+#include <atf-c.h>
+
+struct nl_parsed_gif {
+ struct sockaddr *ifla_local;
+ struct sockaddr *ifla_remote;
+ uint32_t ifla_flags;
+};
+
+struct nla_gif_info {
+ const char *kind;
+ struct nl_parsed_gif data;
+};
+
+struct nla_gif_link {
+ uint32_t ifi_index;
+ struct nla_gif_info linkinfo;
+};
+
+#define _OUT(_field) offsetof(struct nl_parsed_gif, _field)
+static const struct snl_attr_parser nla_p_gif[] = {
+ { .type = IFLA_IPTUN_LOCAL, .off = _OUT(ifla_local), .cb = snl_attr_get_ip },
+ { .type = IFLA_IPTUN_REMOTE, .off = _OUT(ifla_remote), .cb = snl_attr_get_ip },
+ { .type = IFLA_IPTUN_FLAGS, .off = _OUT(ifla_flags), .cb = snl_attr_get_uint32 },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER(gif_linkinfo_data_parser, nla_p_gif);
+
+#define _OUT(_field) offsetof(struct nla_gif_info, _field)
+static const struct snl_attr_parser ap_gif_linkinfo[] = {
+ { .type = IFLA_INFO_KIND, .off = _OUT(kind), .cb = snl_attr_get_string },
+ { .type = IFLA_INFO_DATA, .off = _OUT(data),
+ .arg = &gif_linkinfo_data_parser, .cb = snl_attr_get_nested },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER(gif_linkinfo_parser, ap_gif_linkinfo);
+
+#define _IN(_field) offsetof(struct ifinfomsg, _field)
+#define _OUT(_field) offsetof(struct nla_gif_link, _field)
+static const struct snl_attr_parser ap_gif_link[] = {
+ { .type = IFLA_LINKINFO, .off = _OUT(linkinfo),
+ .arg = &gif_linkinfo_parser, .cb = snl_attr_get_nested },
+};
+
+static const struct snl_field_parser fp_gif_link[] = {
+ { .off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 },
+};
+#undef _IN
+#undef _OUT
+SNL_DECLARE_PARSER(gif_parser, struct ifinfomsg, fp_gif_link, ap_gif_link);
+
+ATF_TC(test_rtnl_gif);
+ATF_TC_HEAD(test_rtnl_gif, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "test gif interface using netlink");
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "require.kmods", "netlink if_gif");
+}
+
+ATF_TC_BODY(test_rtnl_gif, tc)
+{
+ struct snl_state ss;
+ struct snl_writer nw;
+ struct nlmsghdr *hdr, *rx_hdr;
+ struct in_addr src, dst;
+ struct nla_gif_link lattrs = {};
+ struct nl_parsed_gif attrs = {};
+ struct snl_errmsg_data e = {};
+ struct ifinfomsg *ifmsg;
+ int off, off2;
+
+ ATF_REQUIRE_MSG(snl_init(&ss, NETLINK_ROUTE), "snl_init() failed");
+
+ /* Create gif interface */
+ snl_init_writer(&ss, &nw);
+ ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_NEWLINK)) != NULL);
+ hdr->nlmsg_flags |= (NLM_F_CREATE | NLM_F_EXCL | NLM_F_REQUEST | NLM_F_ACK);
+ snl_reserve_msg_object(&nw, struct ifinfomsg);
+
+ /* Create parameters */
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gif10");
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gif");
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+
+ inet_pton(AF_INET, "127.0.0.1", &src);
+ inet_pton(AF_INET, "127.0.0.2", &dst);
+ snl_add_msg_attr_ip4(&nw, IFLA_IPTUN_LOCAL, &src);
+ snl_add_msg_attr_ip4(&nw, IFLA_IPTUN_REMOTE, &dst);
+ snl_add_msg_attr_u32(&nw, IFLA_IPTUN_FLAGS, (GIF_NOCLAMP | GIF_IGNORE_SOURCE));
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
+ ATF_REQUIRE(snl_send_message(&ss, hdr));
+ ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
+ ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e));
+ ATF_REQUIRE_INTEQ(e.error, 0);
+
+ /* Dump gif interface */
+ snl_init_writer(&ss, &nw);
+ ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_GETLINK)) != NULL);
+ hdr->nlmsg_flags |= NLM_F_DUMP;
+ snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, "gif10");
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gif");
+ snl_end_attr_nested(&nw, off);
+
+ ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
+ ATF_REQUIRE(snl_send_message(&ss, hdr));
+
+ /* Check parameters */
+ ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
+ ATF_CHECK(snl_parse_nlmsg(&ss, rx_hdr, &gif_parser, &lattrs));
+ attrs = lattrs.linkinfo.data;
+ ATF_CHECK_STREQ(lattrs.linkinfo.kind, "gif");
+ ATF_CHECK_INTEQ(attrs.ifla_flags, (GIF_NOCLAMP | GIF_IGNORE_SOURCE));
+
+ /* Delete gif interface */
+ snl_init_writer(&ss, &nw);
+ ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_DELLINK)) != NULL);
+ hdr->nlmsg_flags |= (NLM_F_ACK | NLM_F_REQUEST);
+ ATF_REQUIRE((ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg)) != NULL);
+ ifmsg->ifi_index = lattrs.ifi_index;
+ ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
+ ATF_REQUIRE(snl_send_message(&ss, hdr));
+ ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
+ ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e));
+ ATF_REQUIRE_INTEQ(e.error, 0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, test_rtnl_gif);
+
+ return (atf_no_error());
+}
+

File Metadata

Mime Type
text/plain
Expires
Wed, Aug 5, 7:03 PM (9 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35971397
Default Alt Text
D57666.id181565.diff (17 KB)

Event Timeline