Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/ipgre.c        IPGRE Link Info
      3  *
      4  *      This library is free software; you can redistribute it and/or
      5  *      modify it under the terms of the GNU Lesser General Public
      6  *      License as published by the Free Software Foundation version 2.1
      7  *      of the License.
      8  *
      9  * Copyright (c) 2014 Susant Sahani <susant (at) redhat.com>
     10  */
     11 
     12 /**
     13  * @ingroup link
     14  * @defgroup ipgre IPGRE
     15  * ipgre link module
     16  *
     17  * @details
     18  * \b Link Type Name: "ipgre"
     19  *
     20  * @route_doc{link_ipgre, IPGRE Documentation}
     21  *
     22  * @{
     23  */
     24 
     25 #include <netlink-private/netlink.h>
     26 #include <netlink/netlink.h>
     27 #include <netlink/attr.h>
     28 #include <netlink/utils.h>
     29 #include <netlink/object.h>
     30 #include <netlink/route/rtnl.h>
     31 #include <netlink-private/route/link/api.h>
     32 #include <linux/if_tunnel.h>
     33 
     34 #define IPGRE_ATTR_LINK          (1 << 0)
     35 #define IPGRE_ATTR_IFLAGS        (1 << 1)
     36 #define IPGRE_ATTR_OFLAGS        (1 << 2)
     37 #define IPGRE_ATTR_IKEY          (1 << 3)
     38 #define IPGRE_ATTR_OKEY          (1 << 4)
     39 #define IPGRE_ATTR_LOCAL         (1 << 5)
     40 #define IPGRE_ATTR_REMOTE        (1 << 6)
     41 #define IPGRE_ATTR_TTL           (1 << 7)
     42 #define IPGRE_ATTR_TOS           (1 << 8)
     43 #define IPGRE_ATTR_PMTUDISC      (1 << 9)
     44 
     45 struct ipgre_info
     46 {
     47 	uint8_t    ttl;
     48 	uint8_t    tos;
     49 	uint8_t    pmtudisc;
     50 	uint16_t   iflags;
     51 	uint16_t   oflags;
     52 	uint32_t   ikey;
     53 	uint32_t   okey;
     54 	uint32_t   link;
     55 	uint32_t   local;
     56 	uint32_t   remote;
     57 	uint32_t   ipgre_mask;
     58 };
     59 
     60 static  struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = {
     61 	[IFLA_GRE_LINK]     = { .type = NLA_U32 },
     62 	[IFLA_GRE_IFLAGS]   = { .type = NLA_U16 },
     63 	[IFLA_GRE_OFLAGS]   = { .type = NLA_U16 },
     64 	[IFLA_GRE_IKEY]     = { .type = NLA_U32 },
     65 	[IFLA_GRE_OKEY]     = { .type = NLA_U32 },
     66 	[IFLA_GRE_LOCAL]    = { .type = NLA_U32 },
     67 	[IFLA_GRE_REMOTE]   = { .type = NLA_U32 },
     68 	[IFLA_GRE_TTL]      = { .type = NLA_U8 },
     69 	[IFLA_GRE_TOS]      = { .type = NLA_U8 },
     70 	[IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
     71 };
     72 
     73 static int ipgre_alloc(struct rtnl_link *link)
     74 {
     75 	struct ipgre_info *ipgre;
     76 
     77 	ipgre = calloc(1, sizeof(*ipgre));
     78 	if (!ipgre)
     79 		return -NLE_NOMEM;
     80 
     81 	link->l_info = ipgre;
     82 
     83 	return 0;
     84 }
     85 
     86 static int ipgre_parse(struct rtnl_link *link, struct nlattr *data,
     87 		       struct nlattr *xstats)
     88 {
     89 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
     90 	struct ipgre_info *ipgre;
     91 	int err;
     92 
     93 	NL_DBG(3, "Parsing IPGRE link info");
     94 
     95 	err = nla_parse_nested(tb, IFLA_GRE_MAX, data, ipgre_policy);
     96 	if (err < 0)
     97 		goto errout;
     98 
     99 	err = ipgre_alloc(link);
    100 	if (err < 0)
    101 		goto errout;
    102 
    103 	ipgre = link->l_info;
    104 
    105 	if (tb[IFLA_GRE_LINK]) {
    106 		ipgre->link = nla_get_u32(tb[IFLA_GRE_LINK]);
    107 		ipgre->ipgre_mask |= IPGRE_ATTR_LINK;
    108 	}
    109 
    110 	if (tb[IFLA_GRE_IFLAGS]) {
    111 		ipgre->iflags = nla_get_u16(tb[IFLA_GRE_IFLAGS]);
    112 		ipgre->ipgre_mask |= IPGRE_ATTR_IFLAGS;
    113 	}
    114 
    115 	if (tb[IFLA_GRE_OFLAGS]) {
    116 		ipgre->oflags = nla_get_u16(tb[IFLA_GRE_OFLAGS]);
    117 		ipgre->ipgre_mask |= IPGRE_ATTR_OFLAGS;
    118 	}
    119 
    120 	if (tb[IFLA_GRE_IKEY]) {
    121 		ipgre->ikey = nla_get_u32(tb[IFLA_GRE_IKEY]);
    122 		ipgre->ipgre_mask |= IPGRE_ATTR_IKEY;
    123 	}
    124 
    125 	if (tb[IFLA_GRE_OKEY]) {
    126 		ipgre->okey = nla_get_u32(tb[IFLA_GRE_OKEY]);
    127 		ipgre->ipgre_mask |= IPGRE_ATTR_OKEY;
    128 	}
    129 
    130 	if (tb[IFLA_GRE_LOCAL]) {
    131 		ipgre->local = nla_get_u32(tb[IFLA_GRE_LOCAL]);
    132 		ipgre->ipgre_mask |= IPGRE_ATTR_LOCAL;
    133 	}
    134 
    135 	if (tb[IFLA_GRE_LOCAL]) {
    136 		ipgre->remote = nla_get_u32(tb[IFLA_GRE_LOCAL]);
    137 		ipgre->ipgre_mask |= IPGRE_ATTR_REMOTE;
    138 	}
    139 
    140 	if (tb[IFLA_GRE_TTL]) {
    141 		ipgre->ttl = nla_get_u8(tb[IFLA_GRE_TTL]);
    142 		ipgre->ipgre_mask |= IPGRE_ATTR_TTL;
    143 	}
    144 
    145 	if (tb[IFLA_GRE_TOS]) {
    146 		ipgre->tos = nla_get_u8(tb[IFLA_GRE_TOS]);
    147 		ipgre->ipgre_mask |= IPGRE_ATTR_TOS;
    148 	}
    149 
    150 	if (tb[IFLA_GRE_PMTUDISC]) {
    151 		ipgre->pmtudisc = nla_get_u8(tb[IFLA_GRE_PMTUDISC]);
    152 		ipgre->ipgre_mask |= IPGRE_ATTR_PMTUDISC;
    153 	}
    154 
    155 	err = 0;
    156 
    157  errout:
    158 	return err;
    159 }
    160 
    161 static int ipgre_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
    162 {
    163 	struct ipgre_info *ipgre = link->l_info;
    164 	struct nlattr *data;
    165 
    166 	data = nla_nest_start(msg, IFLA_INFO_DATA);
    167 	if (!data)
    168 		return -NLE_MSGSIZE;
    169 
    170 	if (ipgre->ipgre_mask & IPGRE_ATTR_LINK)
    171 		NLA_PUT_U32(msg, IFLA_GRE_LINK, ipgre->link);
    172 
    173 	if (ipgre->ipgre_mask & IFLA_GRE_IFLAGS)
    174 		NLA_PUT_U16(msg, IFLA_GRE_IFLAGS, ipgre->iflags);
    175 
    176 	if (ipgre->ipgre_mask & IFLA_GRE_OFLAGS)
    177 		NLA_PUT_U16(msg, IFLA_GRE_OFLAGS, ipgre->oflags);
    178 
    179 	if (ipgre->ipgre_mask & IPGRE_ATTR_IKEY)
    180 		NLA_PUT_U32(msg, IFLA_GRE_IKEY, ipgre->ikey);
    181 
    182 	if (ipgre->ipgre_mask & IPGRE_ATTR_OKEY)
    183 		NLA_PUT_U32(msg, IFLA_GRE_OKEY, ipgre->okey);
    184 
    185 	if (ipgre->ipgre_mask & IPGRE_ATTR_LOCAL)
    186 		NLA_PUT_U32(msg, IFLA_GRE_LOCAL, ipgre->local);
    187 
    188 	if (ipgre->ipgre_mask & IPGRE_ATTR_REMOTE)
    189 		NLA_PUT_U32(msg, IFLA_GRE_REMOTE, ipgre->remote);
    190 
    191 	if (ipgre->ipgre_mask & IPGRE_ATTR_TTL)
    192 		NLA_PUT_U8(msg, IFLA_GRE_TTL, ipgre->ttl);
    193 
    194 	if (ipgre->ipgre_mask & IPGRE_ATTR_TOS)
    195 		NLA_PUT_U8(msg, IFLA_GRE_TOS, ipgre->tos);
    196 
    197 	if (ipgre->ipgre_mask & IPGRE_ATTR_PMTUDISC)
    198 		NLA_PUT_U8(msg, IFLA_GRE_PMTUDISC, ipgre->pmtudisc);
    199 
    200 	nla_nest_end(msg, data);
    201 
    202  nla_put_failure:
    203 
    204 	return 0;
    205 }
    206 
    207 static void ipgre_free(struct rtnl_link *link)
    208 {
    209 	struct ipgre_info *ipgre = link->l_info;
    210 
    211 	free(ipgre);
    212 	link->l_info = NULL;
    213 }
    214 
    215 static void ipgre_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
    216 {
    217 	nl_dump(p, "ipgre : %s", link->l_name);
    218 }
    219 
    220 static void ipgre_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
    221 {
    222 	struct ipgre_info *ipgre = link->l_info;
    223 	char *name, addr[INET_ADDRSTRLEN];
    224 
    225 	if (ipgre->ipgre_mask & IPGRE_ATTR_LINK) {
    226 		nl_dump(p, "      link ");
    227 		name = rtnl_link_get_name(link);
    228 		if (name)
    229 			nl_dump_line(p, "%s\n", name);
    230 		else
    231 			nl_dump_line(p, "%u\n", ipgre->link);
    232 	}
    233 
    234 	if (ipgre->ipgre_mask & IPGRE_ATTR_IFLAGS) {
    235 		nl_dump(p, "      iflags ");
    236 		nl_dump_line(p, "%x\n", ipgre->iflags);
    237 	}
    238 
    239 	if (ipgre->ipgre_mask & IPGRE_ATTR_OFLAGS) {
    240 		nl_dump(p, "      oflags ");
    241 		nl_dump_line(p, "%x\n", ipgre->oflags);
    242 	}
    243 
    244 	if (ipgre->ipgre_mask & IPGRE_ATTR_IKEY) {
    245 		nl_dump(p, "    ikey   ");
    246 		nl_dump_line(p, "%x\n",ipgre->ikey);
    247 	}
    248 
    249 	if (ipgre->ipgre_mask & IPGRE_ATTR_OKEY) {
    250 		nl_dump(p, "      okey ");
    251 		nl_dump_line(p, "%x\n", ipgre->okey);
    252 	}
    253 
    254 	if (ipgre->ipgre_mask & IPGRE_ATTR_LOCAL) {
    255 		nl_dump(p, "      local ");
    256 		if(inet_ntop(AF_INET, &ipgre->local, addr, sizeof(addr)))
    257 			nl_dump_line(p, "%s\n", addr);
    258 		else
    259 			nl_dump_line(p, "%#x\n", ntohs(ipgre->local));
    260 	}
    261 
    262 	if (ipgre->ipgre_mask & IPGRE_ATTR_REMOTE) {
    263 		nl_dump(p, "      remote ");
    264 		if(inet_ntop(AF_INET, &ipgre->remote, addr, sizeof(addr)))
    265 			nl_dump_line(p, "%s\n", addr);
    266 		else
    267 			nl_dump_line(p, "%#x\n", ntohs(ipgre->remote));
    268 	}
    269 
    270 	if (ipgre->ipgre_mask & IPGRE_ATTR_TTL) {
    271 		nl_dump(p, "      ttl ");
    272 		nl_dump_line(p, "%u\n", ipgre->ttl);
    273 	}
    274 
    275 	if (ipgre->ipgre_mask & IPGRE_ATTR_TOS) {
    276 		nl_dump(p, "      tos ");
    277 		nl_dump_line(p, "%u\n", ipgre->tos);
    278 	}
    279 
    280 	if (ipgre->ipgre_mask & IPGRE_ATTR_PMTUDISC) {
    281 		nl_dump(p, "      pmtudisc ");
    282 		nl_dump_line(p, "enabled (%#x)\n", ipgre->pmtudisc);
    283 	}
    284 }
    285 
    286 static int ipgre_clone(struct rtnl_link *dst, struct rtnl_link *src)
    287 {
    288 	struct ipgre_info *ipgre_dst, *ipgre_src = src->l_info;
    289 	int err;
    290 
    291 	dst->l_info = NULL;
    292 
    293 	err = rtnl_link_set_type(dst, "gre");
    294 	if (err < 0)
    295 		return err;
    296 
    297 	ipgre_dst = dst->l_info;
    298 
    299 	if (!ipgre_dst || !ipgre_src)
    300 		BUG();
    301 
    302 	memcpy(ipgre_dst, ipgre_src, sizeof(struct ipgre_info));
    303 
    304 	return 0;
    305 }
    306 
    307 static struct rtnl_link_info_ops ipgre_info_ops = {
    308 	.io_name                = "gre",
    309 	.io_alloc               = ipgre_alloc,
    310 	.io_parse               = ipgre_parse,
    311 	.io_dump = {
    312 		[NL_DUMP_LINE]  = ipgre_dump_line,
    313 		[NL_DUMP_DETAILS] = ipgre_dump_details,
    314 	},
    315 	.io_clone               = ipgre_clone,
    316 	.io_put_attrs           = ipgre_put_attrs,
    317 	.io_free                = ipgre_free,
    318 };
    319 
    320 #define IS_IPGRE_LINK_ASSERT(link)                                          \
    321         if ((link)->l_info_ops != &ipgre_info_ops) {                        \
    322                 APPBUG("Link is not a ipgre link. set type \"gre\" first.");\
    323                 return -NLE_OPNOTSUPP;                                      \
    324         }
    325 
    326 struct rtnl_link *rtnl_link_ipgre_alloc(void)
    327 {
    328 	struct rtnl_link *link;
    329 	int err;
    330 
    331 	link = rtnl_link_alloc();
    332 	if (!link)
    333 		return NULL;
    334 
    335 	err = rtnl_link_set_type(link, "gre");
    336 	if (err < 0) {
    337 		rtnl_link_put(link);
    338 		return NULL;
    339 	}
    340 
    341 	return link;
    342 }
    343 
    344 /**
    345  * Check if link is a IPGRE link
    346  * @arg link            Link object
    347  *
    348  * @return True if link is a IPGRE link, otherwise 0 is returned.
    349  */
    350 int rtnl_link_is_ipgre(struct rtnl_link *link)
    351 {
    352 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "gre");
    353 }
    354 /**
    355  * Create a new ipip tunnel device
    356  * @arg sock            netlink socket
    357  * @arg name            name of the tunnel deviceL
    358  *
    359  * Creates a new ipip tunnel device in the kernel
    360  * @return 0 on success or a negative error code
    361  */
    362 int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name)
    363 {
    364 	struct rtnl_link *link;
    365 	int err;
    366 
    367 	link = rtnl_link_ipgre_alloc();
    368 	if (!link)
    369 		return -NLE_NOMEM;
    370 
    371 	if(name)
    372 		rtnl_link_set_name(link, name);
    373 
    374 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
    375 	rtnl_link_put(link);
    376 
    377 	return err;
    378 }
    379 /**
    380  * Set IPGRE tunnel interface index
    381  * @arg link            Link object
    382  * @arg index           interface index
    383  *
    384  * @return 0 on success or a negative error code
    385  */
    386 int rtnl_link_ipgre_set_link(struct rtnl_link *link,  uint32_t index)
    387 {
    388 	struct ipgre_info *ipgre = link->l_info;
    389 
    390 	IS_IPGRE_LINK_ASSERT(link);
    391 
    392 	ipgre->link = index;
    393 	ipgre->ipgre_mask |= IPGRE_ATTR_LINK;
    394 
    395 	return 0;
    396 }
    397 
    398 /**
    399  * Get IPGRE tunnel interface index
    400  * @arg link            Link object
    401  *
    402  * @return interface index
    403  */
    404 uint32_t rtnl_link_ipgre_get_link(struct rtnl_link *link)
    405 {
    406 	struct ipgre_info *ipgre = link->l_info;
    407 
    408 	IS_IPGRE_LINK_ASSERT(link);
    409 
    410 	return ipgre->link;
    411 }
    412 
    413 /**
    414  * Set IPGRE tunnel set iflags
    415  * @arg link            Link object
    416  * @arg iflags          gre iflags
    417  *
    418  * @return 0 on success or a negative error code
    419  */
    420 int rtnl_link_ipgre_set_iflags(struct rtnl_link *link, uint16_t iflags)
    421 {
    422 	struct ipgre_info *ipgre = link->l_info;
    423 
    424 	IS_IPGRE_LINK_ASSERT(link);
    425 
    426 	ipgre->iflags = iflags;
    427 	ipgre->ipgre_mask |= IPGRE_ATTR_IFLAGS;
    428 
    429 	return 0;
    430 }
    431 
    432 /**
    433  * Get IPGRE tunnel iflags
    434  * @arg link            Link object
    435  *
    436  * @return iflags
    437  */
    438 uint16_t rtnl_link_ipgre_get_iflags(struct rtnl_link *link)
    439 {
    440 	struct ipgre_info *ipgre = link->l_info;
    441 
    442 	IS_IPGRE_LINK_ASSERT(link);
    443 
    444 	return ipgre->iflags;
    445 }
    446 
    447 /**
    448  * Set IPGRE tunnel set oflags
    449  * @arg link            Link object
    450  * @arg iflags          gre oflags
    451  *
    452  * @return 0 on success or a negative error code
    453  */
    454 int rtnl_link_ipgre_set_oflags(struct rtnl_link *link, uint16_t oflags)
    455 {
    456 	struct ipgre_info *ipgre = link->l_info;
    457 
    458 	IS_IPGRE_LINK_ASSERT(link);
    459 
    460 	ipgre->oflags = oflags;
    461 	ipgre->ipgre_mask |= IPGRE_ATTR_OFLAGS;
    462 
    463 	return 0;
    464 }
    465 
    466 /**
    467  * Get IPGRE tunnel oflags
    468  * @arg link            Link object
    469  *
    470  * @return oflags
    471  */
    472 uint16_t rtnl_link_ipgre_get_oflags(struct rtnl_link *link)
    473 {
    474 	struct ipgre_info *ipgre = link->l_info;
    475 
    476 	IS_IPGRE_LINK_ASSERT(link);
    477 
    478 	return ipgre->oflags;
    479 }
    480 
    481 /**
    482  * Set IPGRE tunnel set ikey
    483  * @arg link            Link object
    484  * @arg ikey            gre ikey
    485  *
    486  * @return 0 on success or a negative error code
    487  */
    488 int rtnl_link_ipgre_set_ikey(struct rtnl_link *link, uint32_t ikey)
    489 {
    490 	struct ipgre_info *ipgre = link->l_info;
    491 
    492 	IS_IPGRE_LINK_ASSERT(link);
    493 
    494 	ipgre->ikey = ikey;
    495 	ipgre->ipgre_mask |= IPGRE_ATTR_IKEY;
    496 
    497 	return 0;
    498 }
    499 
    500 /**
    501  * Get IPGRE tunnel ikey
    502  * @arg link            Link object
    503  *
    504  * @return ikey
    505  */
    506 uint32_t rtnl_link_ipgre_get_ikey(struct rtnl_link *link)
    507 {
    508 	struct ipgre_info *ipgre = link->l_info;
    509 
    510 	IS_IPGRE_LINK_ASSERT(link);
    511 
    512 	return ipgre->ikey;
    513 }
    514 
    515 /**
    516  * Set IPGRE tunnel set okey
    517  * @arg link            Link object
    518  * @arg okey            gre okey
    519  *
    520  * @return 0 on success or a negative error code
    521  */
    522 int rtnl_link_ipgre_set_okey(struct rtnl_link *link, uint32_t okey)
    523 {
    524 	struct ipgre_info *ipgre = link->l_info;
    525 
    526 	IS_IPGRE_LINK_ASSERT(link);
    527 
    528 	ipgre->okey = okey;
    529 	ipgre->ipgre_mask |= IPGRE_ATTR_OKEY;
    530 
    531 	return 0;
    532 }
    533 
    534 /**
    535  * Get IPGRE tunnel okey
    536  * @arg link            Link object
    537  *
    538  * @return okey value
    539  */
    540 uint32_t rtnl_link_ipgre_get_okey(struct rtnl_link *link)
    541 {
    542 	struct ipgre_info *ipgre = link->l_info;
    543 
    544 	IS_IPGRE_LINK_ASSERT(link);
    545 
    546 	return ipgre->okey;
    547 }
    548 
    549 /**
    550  * Set IPGRE tunnel local address
    551  * @arg link            Link object
    552  * @arg addr            local address
    553  *
    554  * @return 0 on success or a negative error code
    555  */
    556 int rtnl_link_ipgre_set_local(struct rtnl_link *link, uint32_t addr)
    557 {
    558 	struct ipgre_info *ipgre = link->l_info;
    559 
    560 	IS_IPGRE_LINK_ASSERT(link);
    561 
    562 	ipgre->local = addr;
    563 	ipgre->ipgre_mask |= IPGRE_ATTR_LOCAL;
    564 
    565 	return 0;
    566 }
    567 
    568 /**
    569  * Get IPGRE tunnel local address
    570  * @arg link            Link object
    571  *
    572  * @return local address
    573  */
    574 uint32_t rtnl_link_ipgre_get_local(struct rtnl_link *link)
    575 {
    576 	struct ipgre_info *ipgre = link->l_info;
    577 
    578 	IS_IPGRE_LINK_ASSERT(link);
    579 
    580 	return ipgre->local;
    581 }
    582 
    583 /**
    584  * Set IPGRE tunnel remote address
    585  * @arg link            Link object
    586  * @arg remote          remote address
    587  *
    588  * @return 0 on success or a negative error code
    589  */
    590 int rtnl_link_ipgre_set_remote(struct rtnl_link *link, uint32_t remote)
    591 {
    592 	struct ipgre_info *ipgre = link->l_info;
    593 
    594 	IS_IPGRE_LINK_ASSERT(link);
    595 
    596 	ipgre->remote = remote;
    597 	ipgre->ipgre_mask |= IPGRE_ATTR_REMOTE;
    598 
    599 	return 0;
    600 }
    601 
    602 /**
    603  * Get IPGRE tunnel remote address
    604  * @arg link            Link object
    605  *
    606  * @return remote address  on success or a negative error code
    607  */
    608 uint32_t rtnl_link_ipgre_get_remote(struct rtnl_link *link)
    609 {
    610 	struct ipgre_info *ipgre = link->l_info;
    611 
    612 	IS_IPGRE_LINK_ASSERT(link);
    613 
    614 	return ipgre->remote;
    615 }
    616 
    617 /**
    618  * Set IPGRE tunnel ttl
    619  * @arg link            Link object
    620  * @arg ttl             tunnel ttl
    621  *
    622  * @return 0 on success or a negative error code
    623  */
    624 int rtnl_link_ipgre_set_ttl(struct rtnl_link *link, uint8_t ttl)
    625 {
    626 	struct ipgre_info *ipgre = link->l_info;
    627 
    628 	IS_IPGRE_LINK_ASSERT(link);
    629 
    630 	ipgre->ttl = ttl;
    631 	ipgre->ipgre_mask |= IPGRE_ATTR_TTL;
    632 
    633 	return 0;
    634 }
    635 
    636 /**
    637  * Set IPGRE tunnel ttl
    638  * @arg link            Link object
    639  *
    640  * @return ttl value
    641  */
    642 uint8_t rtnl_link_ipgre_get_ttl(struct rtnl_link *link)
    643 {
    644 	struct ipgre_info *ipgre = link->l_info;
    645 
    646 	IS_IPGRE_LINK_ASSERT(link);
    647 
    648 	return ipgre->ttl;
    649 }
    650 
    651 /**
    652  * Set IPGRE tunnel tos
    653  * @arg link            Link object
    654  * @arg tos             tunnel tos
    655  *
    656  * @return 0 on success or a negative error code
    657  */
    658 int rtnl_link_ipgre_set_tos(struct rtnl_link *link, uint8_t tos)
    659 {
    660 	struct ipgre_info *ipgre = link->l_info;
    661 
    662 	IS_IPGRE_LINK_ASSERT(link);
    663 
    664 	ipgre->tos = tos;
    665 	ipgre->ipgre_mask |= IPGRE_ATTR_TOS;
    666 
    667 	return 0;
    668 }
    669 
    670 /**
    671  * Get IPGRE tunnel tos
    672  * @arg link            Link object
    673  *
    674  * @return tos value
    675  */
    676 uint8_t rtnl_link_ipgre_get_tos(struct rtnl_link *link)
    677 {
    678 	struct ipgre_info *ipgre = link->l_info;
    679 
    680 	IS_IPGRE_LINK_ASSERT(link);
    681 
    682 	return ipgre->tos;
    683 }
    684 
    685 /**
    686  * Set IPGRE tunnel path MTU discovery
    687  * @arg link            Link object
    688  * @arg pmtudisc        path MTU discovery
    689  *
    690  * @return 0 on success or a negative error code
    691  */
    692 int rtnl_link_ipgre_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
    693 {
    694 	struct ipgre_info *ipgre = link->l_info;
    695 
    696 	IS_IPGRE_LINK_ASSERT(link);
    697 
    698 	ipgre->pmtudisc = pmtudisc;
    699 	ipgre->ipgre_mask |= IPGRE_ATTR_PMTUDISC;
    700 
    701 	return 0;
    702 }
    703 
    704 /**
    705  * Get IPGRE path MTU discovery
    706  * @arg link            Link object
    707  *
    708  * @return pmtudisc value
    709  */
    710 uint8_t rtnl_link_get_pmtudisc(struct rtnl_link *link)
    711 {
    712 	struct ipgre_info *ipgre = link->l_info;
    713 
    714 	IS_IPGRE_LINK_ASSERT(link);
    715 
    716 	return ipgre->pmtudisc;
    717 }
    718 
    719 static void __init ipgre_init(void)
    720 {
    721 	rtnl_link_register_info(&ipgre_info_ops);
    722 }
    723 
    724 static void __exit ipgre_exit(void)
    725 {
    726 	rtnl_link_unregister_info(&ipgre_info_ops);
    727 }
    728