Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/sit.c        SIT 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 sit SIT
     15  * sit link module
     16  *
     17  * @details
     18  * \b Link Type Name: "sit"
     19  *
     20  * @route_doc{link_sit, SIT 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 SIT_ATTR_LINK          (1 << 0)
     35 #define SIT_ATTR_LOCAL         (1 << 1)
     36 #define SIT_ATTR_REMOTE        (1 << 2)
     37 #define SIT_ATTR_TTL           (1 << 3)
     38 #define SIT_ATTR_TOS           (1 << 4)
     39 #define SIT_ATTR_PMTUDISC      (1 << 5)
     40 #define SIT_ATTR_FLAGS         (1 << 6)
     41 #define SIT_ATTR_PROTO         (1 << 7)
     42 
     43 struct sit_info
     44 {
     45 	uint8_t    ttl;
     46 	uint8_t    tos;
     47 	uint8_t    pmtudisc;
     48 	uint8_t    proto;
     49 	uint16_t   flags;
     50 	uint32_t   link;
     51 	uint32_t   local;
     52 	uint32_t   remote;
     53 	uint32_t   sit_mask;
     54 };
     55 
     56 static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = {
     57 	[IFLA_IPTUN_LINK]       = { .type = NLA_U32 },
     58 	[IFLA_IPTUN_LOCAL]      = { .type = NLA_U32 },
     59 	[IFLA_IPTUN_REMOTE]     = { .type = NLA_U32 },
     60 	[IFLA_IPTUN_TTL]        = { .type = NLA_U8 },
     61 	[IFLA_IPTUN_TOS]        = { .type = NLA_U8 },
     62 	[IFLA_IPTUN_PMTUDISC]   = { .type = NLA_U8 },
     63 	[IFLA_IPTUN_FLAGS]      = { .type = NLA_U16 },
     64 	[IFLA_IPTUN_PROTO]      = { .type = NLA_U8 },
     65 };
     66 
     67 static int sit_alloc(struct rtnl_link *link)
     68 {
     69 	struct sit_info *sit;
     70 
     71 	sit = calloc(1, sizeof(*sit));
     72 	if (!sit)
     73 		return -NLE_NOMEM;
     74 
     75 	link->l_info = sit;
     76 
     77 	return 0;
     78 }
     79 
     80 static int sit_parse(struct rtnl_link *link, struct nlattr *data,
     81 		     struct nlattr *xstats)
     82 {
     83 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
     84 	struct sit_info *sit;
     85 	int err;
     86 
     87 	NL_DBG(3, "Parsing SIT link info");
     88 
     89 	err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy);
     90 	if (err < 0)
     91 		goto errout;
     92 
     93 	err = sit_alloc(link);
     94 	if (err < 0)
     95 		goto errout;
     96 
     97 	sit = link->l_info;
     98 
     99 	if (tb[IFLA_IPTUN_LINK]) {
    100 		sit->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
    101 		sit->sit_mask |= SIT_ATTR_LINK;
    102 	}
    103 
    104 	if (tb[IFLA_IPTUN_LOCAL]) {
    105 		sit->local = nla_get_u32(tb[IFLA_IPTUN_LOCAL]);
    106 		sit->sit_mask |= SIT_ATTR_LOCAL;
    107 	}
    108 
    109 	if (tb[IFLA_IPTUN_REMOTE]) {
    110 		sit->remote = nla_get_u32(tb[IFLA_IPTUN_REMOTE]);
    111 		sit->sit_mask |= SIT_ATTR_REMOTE;
    112 	}
    113 
    114 	if (tb[IFLA_IPTUN_TTL]) {
    115 		sit->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
    116 		sit->sit_mask |= SIT_ATTR_TTL;
    117 	}
    118 
    119 	if (tb[IFLA_IPTUN_TOS]) {
    120 		sit->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
    121 		sit->sit_mask |= SIT_ATTR_TOS;
    122 	}
    123 
    124 	if (tb[IFLA_IPTUN_PMTUDISC]) {
    125 		sit->pmtudisc = nla_get_u8(tb[IFLA_IPTUN_PMTUDISC]);
    126 		sit->sit_mask |= SIT_ATTR_PMTUDISC;
    127 	}
    128 
    129 	if (tb[IFLA_IPTUN_FLAGS]) {
    130 		sit->flags = nla_get_u16(tb[IFLA_IPTUN_FLAGS]);
    131 		sit->sit_mask |= SIT_ATTR_FLAGS;
    132 	}
    133 
    134 	if (tb[IFLA_IPTUN_PROTO]) {
    135 		sit->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]);
    136 		sit->sit_mask |= SIT_ATTR_PROTO;
    137 	}
    138 
    139 	err = 0;
    140 
    141  errout:
    142 	return err;
    143 }
    144 
    145 static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
    146 {
    147 	struct sit_info *sit = link->l_info;
    148 	struct nlattr *data;
    149 
    150 	data = nla_nest_start(msg, IFLA_INFO_DATA);
    151 	if (!data)
    152 		return -NLE_MSGSIZE;
    153 
    154 	if (sit->sit_mask & SIT_ATTR_LINK)
    155 		NLA_PUT_U32(msg, IFLA_IPTUN_LINK, sit->link);
    156 
    157 	if (sit->sit_mask & SIT_ATTR_LOCAL)
    158 		NLA_PUT_U32(msg, IFLA_IPTUN_LOCAL, sit->local);
    159 
    160 	if (sit->sit_mask & SIT_ATTR_REMOTE)
    161 		NLA_PUT_U32(msg, IFLA_IPTUN_REMOTE, sit->remote);
    162 
    163 	if (sit->sit_mask & SIT_ATTR_TTL)
    164 		NLA_PUT_U8(msg, IFLA_IPTUN_TTL, sit->ttl);
    165 
    166 	if (sit->sit_mask & SIT_ATTR_TOS)
    167 		NLA_PUT_U8(msg, IFLA_IPTUN_TOS, sit->tos);
    168 
    169 	if (sit->sit_mask & SIT_ATTR_PMTUDISC)
    170 		NLA_PUT_U8(msg, IFLA_IPTUN_PMTUDISC, sit->pmtudisc);
    171 
    172 	if (sit->sit_mask & SIT_ATTR_FLAGS)
    173 		NLA_PUT_U16(msg, IFLA_IPTUN_FLAGS, sit->flags);
    174 
    175 	if (sit->sit_mask & SIT_ATTR_PROTO)
    176 		NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto);
    177 
    178 	nla_nest_end(msg, data);
    179 
    180 nla_put_failure:
    181 
    182 	return 0;
    183 }
    184 
    185 static void sit_free(struct rtnl_link *link)
    186 {
    187 	struct sit_info *sit = link->l_info;
    188 
    189 	free(sit);
    190 	link->l_info = NULL;
    191 }
    192 
    193 static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
    194 {
    195 	nl_dump(p, "sit : %s", link->l_name);
    196 }
    197 
    198 static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
    199 {
    200 	struct sit_info *sit = link->l_info;
    201 	char *name, addr[INET_ADDRSTRLEN];
    202 
    203 	if (sit->sit_mask & SIT_ATTR_LINK) {
    204 		nl_dump(p, "      link ");
    205 		name = rtnl_link_get_name(link);
    206 		if (name)
    207 			nl_dump_line(p, "%s\n", name);
    208 		else
    209 			nl_dump_line(p, "%u\n", sit->link);
    210 	}
    211 
    212 	if (sit->sit_mask & SIT_ATTR_LOCAL) {
    213 		nl_dump(p, "      local ");
    214 		if(inet_ntop(AF_INET, &sit->local, addr, sizeof(addr)))
    215 			nl_dump_line(p, "%s\n", addr);
    216 		else
    217 			nl_dump_line(p, "%#x\n", ntohs(sit->local));
    218 	}
    219 
    220 	if (sit->sit_mask & SIT_ATTR_REMOTE) {
    221 		nl_dump(p, "      remote ");
    222 		if(inet_ntop(AF_INET, &sit->remote, addr, sizeof(addr)))
    223 			nl_dump_line(p, "%s\n", addr);
    224 		else
    225 			nl_dump_line(p, "%#x\n", ntohs(sit->remote));
    226 	}
    227 
    228 	if (sit->sit_mask & SIT_ATTR_TTL) {
    229 		nl_dump(p, "      ttl ");
    230 		nl_dump_line(p, "%u\n", sit->ttl);
    231 	}
    232 
    233 	if (sit->sit_mask & SIT_ATTR_TOS) {
    234 		nl_dump(p, "      tos ");
    235 		nl_dump_line(p, "%u\n", sit->tos);
    236 	}
    237 
    238 	if (sit->sit_mask & SIT_ATTR_FLAGS) {
    239 		nl_dump(p, "      flags ");
    240 		nl_dump_line(p, " (%x)\n", sit->flags);
    241 	}
    242 
    243 	if (sit->sit_mask & SIT_ATTR_PROTO) {
    244 		nl_dump(p, "    proto   ");
    245 		nl_dump_line(p, " (%x)\n", sit->proto);
    246 	}
    247 }
    248 
    249 static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src)
    250 {
    251 	struct sit_info *sit_dst, *sit_src = src->l_info;
    252 	int err;
    253 
    254 	dst->l_info = NULL;
    255 
    256 	err = rtnl_link_set_type(dst, "sit");
    257 	if (err < 0)
    258 		return err;
    259 
    260 	sit_dst = dst->l_info;
    261 
    262 	if (!sit_dst || !sit_src)
    263 		return -NLE_NOMEM;
    264 
    265 	memcpy(sit_dst, sit_src, sizeof(struct sit_info));
    266 
    267 	return 0;
    268 }
    269 
    270 static struct rtnl_link_info_ops sit_info_ops = {
    271 	.io_name                = "sit",
    272 	.io_alloc               = sit_alloc,
    273 	.io_parse               = sit_parse,
    274 	.io_dump = {
    275 		[NL_DUMP_LINE]  = sit_dump_line,
    276 		[NL_DUMP_DETAILS] = sit_dump_details,
    277 	},
    278 	.io_clone               = sit_clone,
    279 	.io_put_attrs           = sit_put_attrs,
    280 	.io_free                = sit_free,
    281 };
    282 
    283 #define IS_SIT_LINK_ASSERT(link)                                           \
    284         if ((link)->l_info_ops != &sit_info_ops) {                         \
    285                 APPBUG("Link is not a sit link. set type \"sit\" first."); \
    286                 return -NLE_OPNOTSUPP;                                     \
    287         }
    288 
    289 struct rtnl_link *rtnl_link_sit_alloc(void)
    290 {
    291 	struct rtnl_link *link;
    292 	int err;
    293 
    294 	link = rtnl_link_alloc();
    295 	if (!link)
    296 		return NULL;
    297 
    298 	err = rtnl_link_set_type(link, "sit");
    299 	if (err < 0) {
    300 		rtnl_link_put(link);
    301 		return NULL;
    302 	}
    303 
    304 	return link;
    305 }
    306 
    307 /**
    308  * Check if link is a SIT link
    309  * @arg link            Link object
    310  *
    311  * @return True if link is a SIT link, otherwise false is returned.
    312  */
    313 int rtnl_link_is_sit(struct rtnl_link *link)
    314 {
    315 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "sit");
    316 }
    317 
    318 /**
    319  * Create a new sit tunnel device
    320  * @arg sock            netlink socket
    321  * @arg name            name of the tunnel device
    322  *
    323  * Creates a new sit tunnel device in the kernel
    324  * @return 0 on success or a negative error code
    325  */
    326 int rtnl_link_sit_add(struct nl_sock *sk, const char *name)
    327 {
    328 	struct rtnl_link *link;
    329 	int err;
    330 
    331 	link = rtnl_link_sit_alloc();
    332 	if (!link)
    333 		return -NLE_NOMEM;
    334 
    335 	if(name)
    336 		rtnl_link_set_name(link, name);
    337 
    338 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
    339 	rtnl_link_put(link);
    340 
    341 	return err;
    342 }
    343 
    344 /**
    345  * Set SIT tunnel interface index
    346  * @arg link            Link object
    347  * @arg index           interface index
    348  *
    349  * @return 0 on success or a negative error code
    350  */
    351 int rtnl_link_sit_set_link(struct rtnl_link *link,  uint32_t index)
    352 {
    353 	struct sit_info *sit = link->l_info;
    354 
    355 	IS_SIT_LINK_ASSERT(link);
    356 
    357 	sit->link = index;
    358 	sit->sit_mask |= SIT_ATTR_LINK;
    359 
    360 	return 0;
    361 }
    362 
    363 /**
    364  * Get SIT tunnel interface index
    365  * @arg link            Link object
    366  *
    367  * @return interface index value
    368  */
    369 uint32_t rtnl_link_sit_get_link(struct rtnl_link *link)
    370 {
    371 	struct sit_info *sit = link->l_info;
    372 
    373 	IS_SIT_LINK_ASSERT(link);
    374 
    375 	return sit->link;
    376 }
    377 
    378 /**
    379  * Set SIT tunnel local address
    380  * @arg link            Link object
    381  * @arg addr            local address
    382  *
    383  * @return 0 on success or a negative error code
    384  */
    385 int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr)
    386 {
    387 	struct sit_info *sit = link->l_info;
    388 
    389 	IS_SIT_LINK_ASSERT(link);
    390 
    391 	sit->local = addr;
    392 	sit->sit_mask |= SIT_ATTR_LOCAL;
    393 
    394 	return 0;
    395 }
    396 
    397 /**
    398  * Get SIT tunnel local address
    399  * @arg link            Link object
    400  *
    401  * @return local address value
    402  */
    403 uint32_t rtnl_link_sit_get_local(struct rtnl_link *link)
    404 {
    405 	struct sit_info *sit = link->l_info;
    406 
    407 	IS_SIT_LINK_ASSERT(link);
    408 
    409 	return sit->local;
    410 }
    411 
    412 /**
    413  * Set SIT tunnel remote address
    414  * @arg link            Link object
    415  * @arg remote          remote address
    416  *
    417  * @return 0 on success or a negative error code
    418  */
    419 int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr)
    420 {
    421 	struct sit_info *sit = link->l_info;
    422 
    423 	IS_SIT_LINK_ASSERT(link);
    424 
    425 	sit->remote = addr;
    426 	sit->sit_mask |= SIT_ATTR_REMOTE;
    427 
    428 	return 0;
    429 }
    430 
    431 /**
    432  * Get SIT tunnel remote address
    433  * @arg link            Link object
    434  *
    435  * @return remote address
    436  */
    437 uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link)
    438 {
    439 	struct sit_info *sit = link->l_info;
    440 
    441 	IS_SIT_LINK_ASSERT(link);
    442 
    443 	return sit->remote;
    444 }
    445 
    446 /**
    447  * Set SIT tunnel ttl
    448  * @arg link            Link object
    449  * @arg ttl             tunnel ttl
    450  *
    451  * @return 0 on success or a negative error code
    452  */
    453 int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl)
    454 {
    455 	struct sit_info *sit = link->l_info;
    456 
    457 	IS_SIT_LINK_ASSERT(link);
    458 
    459 	sit->ttl = ttl;
    460 	sit->sit_mask |= SIT_ATTR_TTL;
    461 
    462 	return 0;
    463 }
    464 
    465 /**
    466  * Get SIT tunnel ttl
    467  * @arg link            Link object
    468  *
    469  * @return ttl value
    470  */
    471 uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link)
    472 {
    473 	struct sit_info *sit = link->l_info;
    474 
    475 	IS_SIT_LINK_ASSERT(link);
    476 
    477 	return sit->ttl;
    478 }
    479 
    480 /**
    481  * Set SIT tunnel tos
    482  * @arg link            Link object
    483  * @arg tos             tunnel tos
    484  *
    485  * @return 0 on success or a negative error code
    486  */
    487 int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos)
    488 {
    489 	struct sit_info *sit = link->l_info;
    490 
    491 	IS_SIT_LINK_ASSERT(link);
    492 
    493 	sit->tos = tos;
    494 	sit->sit_mask |= SIT_ATTR_TOS;
    495 
    496 	return 0;
    497 }
    498 
    499 /**
    500  * Get SIT tunnel tos
    501  * @arg link            Link object
    502  *
    503  * @return tos value
    504  */
    505 uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link)
    506 {
    507 	struct sit_info *sit = link->l_info;
    508 
    509 	IS_SIT_LINK_ASSERT(link);
    510 
    511 	return sit->tos;
    512 }
    513 
    514 /**
    515  * Set SIT tunnel path MTU discovery
    516  * @arg link            Link object
    517  * @arg pmtudisc        path MTU discovery
    518  *
    519  * @return 0 on success or a negative error code
    520  */
    521 int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc)
    522 {
    523 	struct sit_info *sit = link->l_info;
    524 
    525 	IS_SIT_LINK_ASSERT(link);
    526 
    527 	sit->pmtudisc = pmtudisc;
    528 	sit->sit_mask |= SIT_ATTR_PMTUDISC;
    529 
    530 	return 0;
    531 }
    532 
    533 /**
    534  * Get SIT path MTU discovery
    535  * @arg link            Link object
    536  *
    537  * @return pmtudisc value
    538  */
    539 uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link)
    540 {
    541 	struct sit_info *sit = link->l_info;
    542 
    543 	IS_SIT_LINK_ASSERT(link);
    544 
    545 	return sit->pmtudisc;
    546 }
    547 
    548 /**
    549  * Set SIT tunnel flags
    550  * @arg link            Link object
    551  * @arg flags           tunnel flags
    552  *
    553  * @return 0 on success or a negative error code
    554  */
    555 int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags)
    556 {
    557 	struct sit_info *sit = link->l_info;
    558 
    559 	IS_SIT_LINK_ASSERT(link);
    560 
    561 	sit->flags = flags;
    562 	sit->sit_mask |= SIT_ATTR_FLAGS;
    563 
    564 	return 0;
    565 }
    566 
    567 /**
    568  * Get SIT path flags
    569  * @arg link            Link object
    570  *
    571  * @return flags value
    572  */
    573 uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link)
    574 {
    575 	struct sit_info *sit = link->l_info;
    576 
    577 	IS_SIT_LINK_ASSERT(link);
    578 
    579 	return sit->flags;
    580 }
    581 
    582 /**
    583  * Set SIT tunnel proto
    584  * @arg link            Link object
    585  * @arg proto           tunnel proto
    586  *
    587  * @return 0 on success or a negative error code
    588  */
    589 int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto)
    590 {
    591 	struct sit_info *sit = link->l_info;
    592 
    593 	IS_SIT_LINK_ASSERT(link);
    594 
    595 	sit->proto = proto;
    596 	sit->sit_mask |= SIT_ATTR_PROTO;
    597 
    598 	return 0;
    599 }
    600 
    601 /**
    602  * Get SIT proto
    603  * @arg link            Link object
    604  *
    605  * @return proto value
    606  */
    607 uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link)
    608 {
    609 	struct sit_info *sit = link->l_info;
    610 
    611 	IS_SIT_LINK_ASSERT(link);
    612 
    613 	return sit->proto;
    614 }
    615 
    616 static void __init sit_init(void)
    617 {
    618 	rtnl_link_register_info(&sit_info_ops);
    619 }
    620 
    621 static void __exit sit_exit(void)
    622 {
    623 	rtnl_link_unregister_info(&sit_info_ops);
    624 }
    625