19#include "nl-default.h"
21#include <linux/if_tunnel.h>
23#include <netlink/netlink.h>
24#include <netlink/attr.h>
25#include <netlink/utils.h>
26#include <netlink/object.h>
27#include <netlink/route/rtnl.h>
28#include <netlink/route/link/ip6tnl.h>
32#include "nl-aux-route/nl-route.h"
34#define IP6_TNL_ATTR_LINK (1 << 0)
35#define IP6_TNL_ATTR_LOCAL (1 << 1)
36#define IP6_TNL_ATTR_REMOTE (1 << 2)
37#define IP6_TNL_ATTR_TTL (1 << 3)
38#define IP6_TNL_ATTR_TOS (1 << 4)
39#define IP6_TNL_ATTR_ENCAPLIMIT (1 << 5)
40#define IP6_TNL_ATTR_FLAGS (1 << 6)
41#define IP6_TNL_ATTR_PROTO (1 << 7)
42#define IP6_TNL_ATTR_FLOWINFO (1 << 8)
43#define IP6_TNL_ATTR_FWMARK (1 << 9)
44#define IP6_TNL_ATTR_CMTD (1 << 10)
54 struct in6_addr local;
55 struct in6_addr remote;
57 uint32_t ip6_tnl_mask;
60static struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
61 [IFLA_IPTUN_LINK] = { .type =
NLA_U32 },
62 [IFLA_IPTUN_LOCAL] = { .minlen =
sizeof(
struct in6_addr) },
63 [IFLA_IPTUN_REMOTE] = { .minlen =
sizeof(
struct in6_addr) },
64 [IFLA_IPTUN_TTL] = { .type =
NLA_U8 },
65 [IFLA_IPTUN_TOS] = { .type =
NLA_U8 },
66 [IFLA_IPTUN_ENCAP_LIMIT] = { .type =
NLA_U8 },
67 [IFLA_IPTUN_FLOWINFO] = { .type =
NLA_U32 },
68 [IFLA_IPTUN_FLAGS] = { .type =
NLA_U32 },
69 [IFLA_IPTUN_PROTO] = { .type =
NLA_U8 },
70 [IFLA_IPTUN_FWMARK] = { .type =
NLA_U32 },
71 [IFLA_IPTUN_COLLECT_METADATA] = { .type =
NLA_FLAG },
74static int ip6_tnl_alloc(
struct rtnl_link *link)
79 memset(link->l_info, 0,
sizeof(*ip6_tnl));
81 ip6_tnl = calloc(1,
sizeof(*ip6_tnl));
85 link->l_info = ip6_tnl;
91static int ip6_tnl_parse(
struct rtnl_link *link,
struct nlattr *data,
92 struct nlattr *xstats)
94 struct nlattr *tb[IFLA_IPTUN_MAX + 1];
98 NL_DBG(3,
"Parsing IP6_TNL link info\n");
104 err = ip6_tnl_alloc(link);
108 ip6_tnl = link->l_info;
110 if (tb[IFLA_IPTUN_LINK]) {
112 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
115 if (tb[IFLA_IPTUN_LOCAL]) {
116 nla_memcpy(&ip6_tnl->local, tb[IFLA_IPTUN_LOCAL],
117 sizeof(
struct in6_addr));
118 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
121 if (tb[IFLA_IPTUN_REMOTE]) {
122 nla_memcpy(&ip6_tnl->remote, tb[IFLA_IPTUN_REMOTE],
123 sizeof(
struct in6_addr));
124 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
127 if (tb[IFLA_IPTUN_TTL]) {
128 ip6_tnl->ttl =
nla_get_u8(tb[IFLA_IPTUN_TTL]);
129 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
132 if (tb[IFLA_IPTUN_TOS]) {
133 ip6_tnl->tos =
nla_get_u8(tb[IFLA_IPTUN_TOS]);
134 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
137 if (tb[IFLA_IPTUN_ENCAP_LIMIT]) {
138 ip6_tnl->encap_limit =
nla_get_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]);
139 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
142 if (tb[IFLA_IPTUN_FLAGS]) {
143 ip6_tnl->flags =
nla_get_u32(tb[IFLA_IPTUN_FLAGS]);
144 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
147 if (tb[IFLA_IPTUN_FLOWINFO]) {
148 ip6_tnl->flowinfo =
nla_get_u32(tb[IFLA_IPTUN_FLOWINFO]);
149 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
152 if (tb[IFLA_IPTUN_PROTO]) {
153 ip6_tnl->proto =
nla_get_u8(tb[IFLA_IPTUN_PROTO]);
154 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
157 if (tb[IFLA_IPTUN_FWMARK]) {
158 ip6_tnl->fwmark =
nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
159 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
162 if (tb[IFLA_IPTUN_COLLECT_METADATA])
163 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_CMTD;
171static int ip6_tnl_put_attrs(
struct nl_msg *msg,
struct rtnl_link *link)
180 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK)
183 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL)
184 NLA_PUT(msg, IFLA_IPTUN_LOCAL,
sizeof(
struct in6_addr),
187 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE)
188 NLA_PUT(msg, IFLA_IPTUN_REMOTE,
sizeof(
struct in6_addr),
191 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL)
192 NLA_PUT_U8(msg, IFLA_IPTUN_TTL, ip6_tnl->ttl);
194 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS)
195 NLA_PUT_U8(msg, IFLA_IPTUN_TOS, ip6_tnl->tos);
197 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT)
198 NLA_PUT_U8(msg, IFLA_IPTUN_ENCAP_LIMIT, ip6_tnl->encap_limit);
200 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS)
201 NLA_PUT_U32(msg, IFLA_IPTUN_FLAGS, ip6_tnl->flags);
203 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO)
204 NLA_PUT_U32(msg, IFLA_IPTUN_FLOWINFO, ip6_tnl->flowinfo);
207 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO)
208 NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, ip6_tnl->proto);
212 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK)
213 NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, ip6_tnl->fwmark);
215 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_CMTD)
224static void ip6_tnl_free(
struct rtnl_link *link)
234 nl_dump(p,
"ip6_tnl : %s", link->l_name);
237static void ip6_tnl_dump_details(
struct rtnl_link *link,
241 char addr[INET6_ADDRSTRLEN];
243 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK) {
244 _nl_auto_rtnl_link
struct rtnl_link *parent = NULL;
250 parent = link_lookup(link->ce_cache, ip6_tnl->link);
255 nl_dump_line(p,
"%s\n", name);
257 nl_dump_line(p,
"%u\n", ip6_tnl->link);
260 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL) {
262 nl_dump_line(p,
"%s\n",
263 _nl_inet_ntop(AF_INET6, &ip6_tnl->local, addr));
266 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE) {
268 nl_dump_line(p,
"%s\n",
269 _nl_inet_ntop(AF_INET6, &ip6_tnl->remote, addr));
272 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL) {
274 nl_dump_line(p,
"%d\n", ip6_tnl->ttl);
277 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS) {
279 nl_dump_line(p,
"%d\n", ip6_tnl->tos);
282 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT) {
284 nl_dump_line(p,
"%d\n", ip6_tnl->encap_limit);
287 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS) {
289 nl_dump_line(p,
" (%x)\n", ip6_tnl->flags);
292 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO) {
294 nl_dump_line(p,
" (%x)\n", ip6_tnl->flowinfo);
297 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO) {
299 nl_dump_line(p,
" (%x)\n", ip6_tnl->proto);
302 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK) {
304 nl_dump_line(p,
"%x\n", ip6_tnl->fwmark);
307 if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_CMTD) {
308 nl_dump(p,
" collect-metadata\n");
314 struct ip6_tnl_info *ip6_tnl_dst, *ip6_tnl_src = src->l_info;
323 ip6_tnl_dst = dst->l_info;
325 if (!ip6_tnl_dst || !ip6_tnl_src)
328 memcpy(ip6_tnl_dst, ip6_tnl_src,
sizeof(
struct ip6_tnl_info));
335 .io_alloc = ip6_tnl_alloc,
336 .io_parse = ip6_tnl_parse,
341 .io_clone = ip6_tnl_clone,
342 .io_put_attrs = ip6_tnl_put_attrs,
343 .io_free = ip6_tnl_free,
346#define IS_IP6_TNL_LINK_ASSERT(link) \
347 if ((link)->l_info_ops != &ip6_tnl_info_ops) { \
348 APPBUG("Link is not a ip6_tnl link. set type \"ip6tnl\" first."); \
349 return -NLE_OPNOTSUPP; \
352struct rtnl_link *rtnl_link_ip6_tnl_alloc(
void)
378 return link->l_info_ops && !strcmp(link->l_info_ops->
io_name,
"ip6tnl");
394 link = rtnl_link_ip6_tnl_alloc();
418 IS_IP6_TNL_LINK_ASSERT(link);
420 ip6_tnl->link = index;
421 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
436 IS_IP6_TNL_LINK_ASSERT(link);
438 return ip6_tnl->link;
452 IS_IP6_TNL_LINK_ASSERT(link);
454 memcpy(&ip6_tnl->local, addr,
sizeof(
struct in6_addr));
455 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
470 IS_IP6_TNL_LINK_ASSERT(link);
472 memcpy(addr, &ip6_tnl->local,
sizeof(
struct in6_addr));
488 IS_IP6_TNL_LINK_ASSERT(link);
490 memcpy(&ip6_tnl->remote, addr,
sizeof(
struct in6_addr));
491 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
506 IS_IP6_TNL_LINK_ASSERT(link);
508 memcpy(addr, &ip6_tnl->remote,
sizeof(
struct in6_addr));
524 IS_IP6_TNL_LINK_ASSERT(link);
527 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
542 IS_IP6_TNL_LINK_ASSERT(link);
558 IS_IP6_TNL_LINK_ASSERT(link);
561 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
576 IS_IP6_TNL_LINK_ASSERT(link);
593 IS_IP6_TNL_LINK_ASSERT(link);
595 ip6_tnl->encap_limit = encap_limit;
596 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
611 IS_IP6_TNL_LINK_ASSERT(link);
613 return ip6_tnl->encap_limit;
627 IS_IP6_TNL_LINK_ASSERT(link);
629 ip6_tnl->flowinfo = flowinfo;
630 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
645 IS_IP6_TNL_LINK_ASSERT(link);
647 return ip6_tnl->flowinfo;
661 IS_IP6_TNL_LINK_ASSERT(link);
663 ip6_tnl->flags = flags;
664 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
679 IS_IP6_TNL_LINK_ASSERT(link);
681 return ip6_tnl->flags;
697 IS_IP6_TNL_LINK_ASSERT(link);
700 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_CMTD;
702 ip6_tnl->ip6_tnl_mask &= ~IP6_TNL_ATTR_CMTD;
719 IS_IP6_TNL_LINK_ASSERT(link);
724 *enable = !!(ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_CMTD);
740 IS_IP6_TNL_LINK_ASSERT(link);
742 ip6_tnl->proto = proto;
743 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
758 IS_IP6_TNL_LINK_ASSERT(link);
760 return ip6_tnl->proto;
774 IS_IP6_TNL_LINK_ASSERT(link);
776 ip6_tnl->fwmark = fwmark;
777 ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
793 IS_IP6_TNL_LINK_ASSERT(link);
795 if (!(ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK))
798 *fwmark = ip6_tnl->fwmark;
803static void _nl_init ip6_tnl_init(
void)
808static void _nl_exit ip6_tnl_exit(
void)
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
#define NLA_PUT_FLAG(msg, attrtype)
Add flag attribute to netlink message.
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
int rtnl_link_ip6_tnl_set_remote(struct rtnl_link *link, struct in6_addr *addr)
Set IP6_TNL tunnel remote address.
uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link)
Get IP6_TNL proto.
uint32_t rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link *link)
Get IP6_TNL flowinfo.
int rtnl_link_is_ip6_tnl(struct rtnl_link *link)
Check if link is a IP6_TNL link.
int rtnl_link_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index)
Set IP6_TNL tunnel interface index.
int rtnl_link_ip6_tnl_add(struct nl_sock *sk, const char *name)
Create a new ip6_tnl tunnel device.
uint8_t rtnl_link_ip6_tnl_get_ttl(struct rtnl_link *link)
Get IP6_TNL tunnel ttl.
int rtnl_link_ip6_tnl_get_remote(struct rtnl_link *link, struct in6_addr *addr)
Get IP6_TNL tunnel remote address.
uint32_t rtnl_link_ip6_tnl_get_flags(struct rtnl_link *link)
Get IP6_TNL path flags.
int rtnl_link_ip6_tnl_get_collect_metadata(struct rtnl_link *link, int *enable)
Get IP6_TNL collect-metadata flag.
int rtnl_link_ip6_tnl_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
Set IP6_TNL tunnel fwmark.
uint8_t rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link *link)
Get IP6_TNL encaplimit.
int rtnl_link_ip6_tnl_set_flags(struct rtnl_link *link, uint32_t flags)
Set IP6_TNL tunnel flags.
int rtnl_link_ip6_tnl_set_local(struct rtnl_link *link, struct in6_addr *addr)
Set IP6_TNL tunnel local address.
int rtnl_link_ip6_tnl_set_ttl(struct rtnl_link *link, uint8_t ttl)
Set IP6_TNL tunnel ttl.
int rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo)
Set IP6_TNL tunnel flowinfo.
int rtnl_link_ip6_tnl_get_local(struct rtnl_link *link, struct in6_addr *addr)
Get IP6_TNL tunnel local address.
int rtnl_link_ip6_tnl_set_tos(struct rtnl_link *link, uint8_t tos)
Set IP6_TNL tunnel tos.
int rtnl_link_ip6_tnl_set_proto(struct rtnl_link *link, uint8_t proto)
Set IP6_TNL tunnel proto.
int rtnl_link_ip6_tnl_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
Get IP6_TNL tunnel fwmark.
int rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link *link, uint8_t encap_limit)
Set IP6_TNL tunnel encap limit.
uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link)
Get IP6_TNL tunnel interface index.
uint8_t rtnl_link_ip6_tnl_get_tos(struct rtnl_link *link)
Get IP6_TNL tunnel tos.
int rtnl_link_ip6_tnl_set_collect_metadata(struct rtnl_link *link, int enable)
Set IP6_TNL collect-metadata flag.
int rtnl_link_register_info(struct rtnl_link_info_ops *ops)
Register operations for a link info type.
int rtnl_link_unregister_info(struct rtnl_link_info_ops *ops)
Unregister operations for a link info type.
int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags)
Add virtual link.
struct rtnl_link * rtnl_link_alloc(void)
Allocate link object.
void rtnl_link_set_name(struct rtnl_link *link, const char *name)
Set name of link object.
char * rtnl_link_get_name(struct rtnl_link *link)
Return name of link object.
void rtnl_link_put(struct rtnl_link *link)
Release a link object reference.
int rtnl_link_set_type(struct rtnl_link *link, const char *type)
Set type of link object.
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
@ NL_DUMP_LINE
Dump object briefly on one line.
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Attribute validation policy.
Available operations to modules implementing a link info type.
char * io_name
Name of link info type, must match name on kernel side.