From eec318f0260f4f081355e802aaa4844b07557d5b Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Fri, 1 Apr 2016 18:18:50 +0800 Subject: ipgre: add support for gretap tunnel Since kernel support both gre/gretap tunnel, so add support for gretap appropriately. Signed-off-by: Haishuang Yan Signed-off-by: Thomas Haller [thaller@redhat.com: modified original patch to move symbols in libnl-route-3.sym to proper section] http://lists.infradead.org/pipermail/libnl/2016-April/002102.html --- include/netlink/route/link/ipgre.h | 2 + lib/route/link/ipgre.c | 103 +++++++++++++++++++++++++++++++++++-- libnl-route-3.sym | 2 + tests/.gitignore | 1 + tests/Makefile.am | 1 + tests/test-create-ipgretap.c | 56 ++++++++++++++++++++ 6 files changed, 160 insertions(+), 5 deletions(-) create mode 100644 tests/test-create-ipgretap.c diff --git a/include/netlink/route/link/ipgre.h b/include/netlink/route/link/ipgre.h index 5a0a295..647c3cf 100644 --- a/include/netlink/route/link/ipgre.h +++ b/include/netlink/route/link/ipgre.h @@ -20,7 +20,9 @@ extern "C" { #endif extern struct rtnl_link *rtnl_link_ipgre_alloc(void); + extern struct rtnl_link *rtnl_link_ipgretap_alloc(void); extern int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name); + extern int rtnl_link_ipgretap_add(struct nl_sock *sk, const char *name); extern int rtnl_link_ipgre_set_link(struct rtnl_link *link, uint32_t index); extern uint32_t rtnl_link_ipgre_get_link(struct rtnl_link *link); diff --git a/lib/route/link/ipgre.c b/lib/route/link/ipgre.c index 7889d11..7be311a 100644 --- a/lib/route/link/ipgre.c +++ b/lib/route/link/ipgre.c @@ -315,6 +315,27 @@ static int ipgre_clone(struct rtnl_link *dst, struct rtnl_link *src) return 0; } +static int ipgretap_clone(struct rtnl_link *dst, struct rtnl_link *src) +{ + struct ipgre_info *ipgre_dst, *ipgre_src = src->l_info; + int err; + + dst->l_info = NULL; + + err = rtnl_link_set_type(dst, "gretap"); + if (err < 0) + return err; + + ipgre_dst = dst->l_info; + + if (!ipgre_dst || !ipgre_src) + BUG(); + + memcpy(ipgre_dst, ipgre_src, sizeof(struct ipgre_info)); + + return 0; +} + static struct rtnl_link_info_ops ipgre_info_ops = { .io_name = "gre", .io_alloc = ipgre_alloc, @@ -328,10 +349,24 @@ static struct rtnl_link_info_ops ipgre_info_ops = { .io_free = ipgre_free, }; -#define IS_IPGRE_LINK_ASSERT(link) \ - if ((link)->l_info_ops != &ipgre_info_ops) { \ - APPBUG("Link is not a ipgre link. set type \"gre\" first.");\ - return -NLE_OPNOTSUPP; \ +static struct rtnl_link_info_ops ipgretap_info_ops = { + .io_name = "gretap", + .io_alloc = ipgre_alloc, + .io_parse = ipgre_parse, + .io_dump = { + [NL_DUMP_LINE] = ipgre_dump_line, + [NL_DUMP_DETAILS] = ipgre_dump_details, + }, + .io_clone = ipgretap_clone, + .io_put_attrs = ipgre_put_attrs, + .io_free = ipgre_free, +}; + +#define IS_IPGRE_LINK_ASSERT(link) \ + if ((link)->l_info_ops != &ipgre_info_ops && \ + (link)->l_info_ops != &ipgretap_info_ops) { \ + APPBUG("Link is not a ipgre link. set type \"gre/gretap\" first.");\ + return -NLE_OPNOTSUPP; \ } struct rtnl_link *rtnl_link_ipgre_alloc(void) @@ -362,8 +397,9 @@ int rtnl_link_is_ipgre(struct rtnl_link *link) { return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gre"); } + /** - * Create a new ipip tunnel device + * Create a new IPGRE tunnel device * @arg sock netlink socket * @arg name name of the tunnel deviceL * @@ -387,6 +423,61 @@ int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name) return err; } + +struct rtnl_link *rtnl_link_ipgretap_alloc(void) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_alloc(); + if (!link) + return NULL; + + err = rtnl_link_set_type(link, "gretap"); + if (err < 0) { + rtnl_link_put(link); + return NULL; + } + + return link; +} + +/** + * Check if link is a IPGRETAP link + * @arg link Link object + * + * @return True if link is a IPGRETAP link, otherwise 0 is returned. + */ +int rtnl_link_is_ipgretap(struct rtnl_link *link) +{ + return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gretap"); +} +/** + * Create a new IPGRETAP tunnel device + * @arg sock netlink socket + * @arg name name of the tunnel deviceL + * + * Creates a new IPGRETAP tunnel device in the kernel + * @return 0 on success or a negative error code + */ +int rtnl_link_ipgretap_add(struct nl_sock *sk, const char *name) +{ + struct rtnl_link *link; + int err; + + link = rtnl_link_ipgretap_alloc(); + if (!link) + return -NLE_NOMEM; + + if(name) + rtnl_link_set_name(link, name); + + err = rtnl_link_add(sk, link, NLM_F_CREATE); + rtnl_link_put(link); + + return err; +} + /** * Set IPGRE tunnel interface index * @arg link Link object @@ -730,9 +821,11 @@ uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link) static void __init ipgre_init(void) { rtnl_link_register_info(&ipgre_info_ops); + rtnl_link_register_info(&ipgretap_info_ops); } static void __exit ipgre_exit(void) { rtnl_link_unregister_info(&ipgre_info_ops); + rtnl_link_unregister_info(&ipgretap_info_ops); } diff --git a/libnl-route-3.sym b/libnl-route-3.sym index 1fd205b..cd2b824 100644 --- a/libnl-route-3.sym +++ b/libnl-route-3.sym @@ -893,6 +893,8 @@ global: rtnl_link_bridge_pvid; rtnl_link_is_macvtap; rtnl_link_is_vrf; + rtnl_link_ipgretap_add; + rtnl_link_ipgretap_alloc; rtnl_link_macvtap_alloc; rtnl_link_macvtap_flags2str; rtnl_link_macvtap_get_flags; diff --git a/tests/.gitignore b/tests/.gitignore index d11450b..9666f27 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,6 +10,7 @@ /test-create-ifb /test-create-ip6tnl /test-create-ipgre +/test-create-ipgretap /test-create-ipip /test-create-ipvlan /test-create-ipvti diff --git a/tests/Makefile.am b/tests/Makefile.am index e764635..5cf43e9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -32,6 +32,7 @@ check_PROGRAMS = \ test-create-bridge \ test-create-ip6tnl \ test-create-ipgre \ + test-create-ipgretap \ test-create-ipip \ test-create-ipvti \ test-create-macvlan \ diff --git a/tests/test-create-ipgretap.c b/tests/test-create-ipgretap.c new file mode 100644 index 0000000..1fe8231 --- /dev/null +++ b/tests/test-create-ipgretap.c @@ -0,0 +1,56 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + struct nl_cache *link_cache; + struct rtnl_link *link; + struct in_addr addr; + struct nl_sock *sk; + int err, if_index; + + sk = nl_socket_alloc(); + if ((err = nl_connect(sk, NETLINK_ROUTE)) < 0) { + nl_perror(err, "Unable to connect socket"); + return err; + } + + err = rtnl_link_alloc_cache(sk, AF_UNSPEC, &link_cache); + if ( err < 0) { + nl_perror(err, "Unable to allocate cache"); + return err; + } + + if_index = rtnl_link_name2i(link_cache, "enp0s5"); + if (!if_index) { + fprintf(stderr, "Unable to lookup enp0s5"); + return -1; + } + + link = rtnl_link_ipgretap_alloc(); + if(!link) { + nl_perror(err, "Unable to allocate link"); + return -1; + + } + rtnl_link_set_name(link, "ipgre-tap"); + rtnl_link_ipgre_set_link(link, if_index); + + inet_pton(AF_INET, "10.211.55.10", &addr.s_addr); + rtnl_link_ipgre_set_local(link, addr.s_addr); + + inet_pton(AF_INET, "10.133.6.33", &addr.s_addr); + rtnl_link_ipgre_set_remote(link, addr.s_addr); + + rtnl_link_ipgre_set_ttl(link, 64); + err = rtnl_link_add(sk, link, NLM_F_CREATE); + if (err < 0) { + nl_perror(err, "Unable to add link"); + return err; + } + + rtnl_link_put(link); + nl_close(sk); + + return 0; +} -- cgit v0.12