diff options
Diffstat (limited to 'lib/route/link/sit.c')
-rw-r--r-- | lib/route/link/sit.c | 323 |
1 files changed, 261 insertions, 62 deletions
diff --git a/lib/route/link/sit.c b/lib/route/link/sit.c index 694c177f..88565137 100644 --- a/lib/route/link/sit.c +++ b/lib/route/link/sit.c @@ -28,6 +28,7 @@ #include <netlink/utils.h> #include <netlink/object.h> #include <netlink/route/rtnl.h> +#include <netlink/route/link/sit.h> #include <netlink-private/route/link/api.h> #include <linux/if_tunnel.h> @@ -39,6 +40,10 @@ #define SIT_ATTR_PMTUDISC (1 << 5) #define SIT_ATTR_FLAGS (1 << 6) #define SIT_ATTR_PROTO (1 << 7) +#define SIT_ATTR_6RD_PREFIX (1 << 8) +#define SIT_ATTR_6RD_RELAY_PREFIX (1 << 9) +#define SIT_ATTR_6RD_PREFIXLEN (1 << 10) +#define SIT_ATTR_6RD_RELAY_PREFIXLEN (1 << 11) struct sit_info { @@ -50,6 +55,10 @@ struct sit_info uint32_t link; uint32_t local; uint32_t remote; + struct in6_addr ip6rd_prefix; + uint32_t ip6rd_relay_prefix; + uint16_t ip6rd_prefixlen; + uint16_t ip6rd_relay_prefixlen; uint32_t sit_mask; }; @@ -62,17 +71,25 @@ static struct nla_policy sit_policy[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + [IFLA_IPTUN_6RD_PREFIX] = { .minlen = sizeof(struct in6_addr) }, + [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 }, + [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, + [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, }; static int sit_alloc(struct rtnl_link *link) { struct sit_info *sit; - sit = calloc(1, sizeof(*sit)); - if (!sit) - return -NLE_NOMEM; + if (link->l_info) + memset(link->l_info, 0, sizeof(*sit)); + else { + sit = calloc(1, sizeof(*sit)); + if (!sit) + return -NLE_NOMEM; - link->l_info = sit; + link->l_info = sit; + } return 0; } @@ -84,7 +101,7 @@ static int sit_parse(struct rtnl_link *link, struct nlattr *data, struct sit_info *sit; int err; - NL_DBG(3, "Parsing SIT link info"); + NL_DBG(3, "Parsing SIT link info\n"); err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, sit_policy); if (err < 0) @@ -136,9 +153,30 @@ static int sit_parse(struct rtnl_link *link, struct nlattr *data, sit->sit_mask |= SIT_ATTR_PROTO; } + if (tb[IFLA_IPTUN_6RD_PREFIX]) { + nla_memcpy(&sit->ip6rd_prefix, tb[IFLA_IPTUN_6RD_PREFIX], + sizeof(struct in6_addr)); + sit->sit_mask |= SIT_ATTR_6RD_PREFIX; + } + + if (tb[IFLA_IPTUN_6RD_RELAY_PREFIX]) { + sit->ip6rd_relay_prefix = nla_get_u32(tb[IFLA_IPTUN_6RD_RELAY_PREFIX]); + sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX; + } + + if (tb[IFLA_IPTUN_6RD_PREFIXLEN]) { + sit->ip6rd_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_PREFIXLEN]); + sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN; + } + + if (tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) { + sit->ip6rd_relay_prefixlen = nla_get_u16(tb[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); + sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN; + } + err = 0; - errout: +errout: return err; } @@ -175,6 +213,18 @@ static int sit_put_attrs(struct nl_msg *msg, struct rtnl_link *link) if (sit->sit_mask & SIT_ATTR_PROTO) NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, sit->proto); + if (sit->sit_mask & SIT_ATTR_6RD_PREFIX) + NLA_PUT(msg, IFLA_IPTUN_6RD_PREFIX, sizeof(struct in6_addr), &sit->ip6rd_prefix); + + if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX) + NLA_PUT_U32(msg, IFLA_IPTUN_6RD_RELAY_PREFIX, sit->ip6rd_relay_prefix); + + if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN) + NLA_PUT_U16(msg, IFLA_IPTUN_6RD_PREFIXLEN, sit->ip6rd_prefixlen); + + if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN) + NLA_PUT_U16(msg, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, sit->ip6rd_relay_prefixlen); + nla_nest_end(msg, data); nla_put_failure: @@ -198,11 +248,17 @@ static void sit_dump_line(struct rtnl_link *link, struct nl_dump_params *p) static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p) { struct sit_info *sit = link->l_info; - char *name, addr[INET_ADDRSTRLEN]; + char *name, addr[INET_ADDRSTRLEN], addr6[INET6_ADDRSTRLEN]; + struct rtnl_link *parent; if (sit->sit_mask & SIT_ATTR_LINK) { nl_dump(p, " link "); - name = rtnl_link_get_name(link); + + name = NULL; + parent = link_lookup(link->ce_cache, sit->link); + if (parent) + name = rtnl_link_get_name(parent); + if (name) nl_dump_line(p, "%s\n", name); else @@ -241,9 +297,35 @@ static void sit_dump_details(struct rtnl_link *link, struct nl_dump_params *p) } if (sit->sit_mask & SIT_ATTR_PROTO) { - nl_dump(p, " proto "); + nl_dump(p, " proto "); nl_dump_line(p, " (%x)\n", sit->proto); } + + if (sit->sit_mask & SIT_ATTR_6RD_PREFIX) { + nl_dump(p, " 6rd_prefix "); + if(inet_ntop(AF_INET6, &sit->ip6rd_prefix, addr6, INET6_ADDRSTRLEN)) + nl_dump_line(p, "%s\n", addr6); + else + nl_dump_line(p, "[unknown]\n"); + } + + if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX) { + nl_dump(p, " 6rd_relay_prefix "); + if(inet_ntop(AF_INET, &sit->ip6rd_relay_prefix, addr, sizeof(addr))) + nl_dump_line(p, "%s\n", addr); + else + nl_dump_line(p, "[unknown]\n"); + } + + if (sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN) { + nl_dump(p, " 6rd_prefixlen "); + nl_dump_line(p, "%d\n", sit->ip6rd_prefixlen); + } + + if (sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIXLEN) { + nl_dump(p, " 6rd_relay_prefixlen "); + nl_dump_line(p, "%d\n", sit->ip6rd_relay_prefixlen); + } } static int sit_clone(struct rtnl_link *dst, struct rtnl_link *src) @@ -280,11 +362,16 @@ static struct rtnl_link_info_ops sit_info_ops = { .io_free = sit_free, }; -#define IS_SIT_LINK_ASSERT(link) \ - if ((link)->l_info_ops != &sit_info_ops) { \ - APPBUG("Link is not a sit link. set type \"sit\" first."); \ - return -NLE_OPNOTSUPP; \ - } +#define IS_SIT_LINK_ASSERT(link, sit) \ + struct sit_info *sit; \ + do { \ + const struct rtnl_link *_link = (link); \ + if (!_link || _link->l_info_ops != &sit_info_ops) { \ + APPBUG("Link is not a sit link. set type \"sit\" first."); \ + return -NLE_OPNOTSUPP; \ + } \ + (sit) = _link->l_info; \ + } while (0) struct rtnl_link *rtnl_link_sit_alloc(void) { @@ -350,9 +437,7 @@ int rtnl_link_sit_add(struct nl_sock *sk, const char *name) */ int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->link = index; sit->sit_mask |= SIT_ATTR_LINK; @@ -368,9 +453,7 @@ int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index) */ uint32_t rtnl_link_sit_get_link(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->link; } @@ -384,9 +467,7 @@ uint32_t rtnl_link_sit_get_link(struct rtnl_link *link) */ int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->local = addr; sit->sit_mask |= SIT_ATTR_LOCAL; @@ -402,9 +483,7 @@ int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr) */ uint32_t rtnl_link_sit_get_local(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->local; } @@ -418,9 +497,7 @@ uint32_t rtnl_link_sit_get_local(struct rtnl_link *link) */ int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->remote = addr; sit->sit_mask |= SIT_ATTR_REMOTE; @@ -436,9 +513,7 @@ int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr) */ uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->remote; } @@ -452,9 +527,7 @@ uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link) */ int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->ttl = ttl; sit->sit_mask |= SIT_ATTR_TTL; @@ -470,9 +543,7 @@ int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl) */ uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->ttl; } @@ -486,9 +557,7 @@ uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link) */ int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->tos = tos; sit->sit_mask |= SIT_ATTR_TOS; @@ -504,9 +573,7 @@ int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos) */ uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->tos; } @@ -520,9 +587,7 @@ uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link) */ int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->pmtudisc = pmtudisc; sit->sit_mask |= SIT_ATTR_PMTUDISC; @@ -538,9 +603,7 @@ int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc) */ uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->pmtudisc; } @@ -554,9 +617,7 @@ uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link) */ int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->flags = flags; sit->sit_mask |= SIT_ATTR_FLAGS; @@ -572,9 +633,7 @@ int rtnl_link_sit_set_flags(struct rtnl_link *link, uint16_t flags) */ uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->flags; } @@ -588,9 +647,7 @@ uint16_t rtnl_link_sit_get_flags(struct rtnl_link *link) */ int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); sit->proto = proto; sit->sit_mask |= SIT_ATTR_PROTO; @@ -606,13 +663,155 @@ int rtnl_link_sit_set_proto(struct rtnl_link *link, uint8_t proto) */ uint8_t rtnl_link_sit_get_proto(struct rtnl_link *link) { - struct sit_info *sit = link->l_info; - - IS_SIT_LINK_ASSERT(link); + IS_SIT_LINK_ASSERT(link, sit); return sit->proto; } +/** + * Set ip6rd prefix + * @arg link Link object + * @arg prefix The IPv6 prefix + * + * @return 0 on success or an error code. + */ +int rtnl_link_sit_set_ip6rd_prefix(struct rtnl_link *link, const struct in6_addr *prefix) +{ + IS_SIT_LINK_ASSERT(link, sit); + + sit->ip6rd_prefix = *prefix; + sit->sit_mask |= SIT_ATTR_6RD_PREFIX; + return 0; +} + +/** + * Get ip6rd prefix + * @arg link Link object + * @arg prefix The output IPv6 prefix + * + * @return 0 on success or an error code. If the property is unset, + * this call fails too. + */ +int rtnl_link_sit_get_ip6rd_prefix(const struct rtnl_link *link, struct in6_addr *prefix) +{ + IS_SIT_LINK_ASSERT(link, sit); + + if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIX)) + return -NLE_NOATTR; + + if (prefix) + *prefix = sit->ip6rd_prefix; + return 0; +} + +/** + * Set ip6rd prefix length + * @arg link Link object + * @arg prefixlen The IPv6 prefix length + * + * @return 0 on success or an error code. + */ +int rtnl_link_sit_set_ip6rd_prefixlen(struct rtnl_link *link, uint16_t prefixlen) +{ + IS_SIT_LINK_ASSERT(link, sit); + + sit->sit_mask |= SIT_ATTR_6RD_PREFIXLEN; + sit->ip6rd_prefixlen = prefixlen; + return 0; +} + +/** + * Get ip6rd prefix length + * @arg link Link object + * @arg prefixlen Output pointer for the prefix length + * + * @return 0 on success or an error code. If the property is unset, + * this call fails. + */ +int rtnl_link_sit_get_ip6rd_prefixlen(struct rtnl_link *link, uint16_t *prefixlen) +{ + IS_SIT_LINK_ASSERT(link, sit); + + if (!(sit->sit_mask & SIT_ATTR_6RD_PREFIXLEN)) + return -NLE_NOATTR; + + if (prefixlen) + *prefixlen = sit->ip6rd_prefixlen; + return 0; +} + +/** + * Set ip6rd relay prefix + * @arg link Link object + * @arg prefix The IPv6 prefix length + * + * @return 0 on success or an error code. + */ +int rtnl_link_sit_set_ip6rd_relay_prefix(struct rtnl_link *link, uint32_t prefix) +{ + IS_SIT_LINK_ASSERT(link, sit); + + sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIX; + sit->ip6rd_relay_prefix = prefix; + return 0; +} + +/** + * Get ip6rd prefix length + * @arg link Link object + * @arg prefixlen Output pointer for the prefix length + * + * @return 0 on success or an error code. If the property is unset, + * this call fails. + */ +int rtnl_link_sit_get_ip6rd_relay_prefix(const struct rtnl_link *link, uint32_t *prefix) +{ + IS_SIT_LINK_ASSERT(link, sit); + + if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX)) + return -NLE_NOATTR; + + if (prefix) + *prefix = sit->ip6rd_relay_prefix; + return 0; +} + +/** + * Set ip6rd relay prefix length + * @arg link Link object + * @arg prefixlen The IPv6 prefix length + * + * @return 0 on success or an error code. + */ +int rtnl_link_sit_set_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t prefixlen) +{ + IS_SIT_LINK_ASSERT(link, sit); + + sit->sit_mask |= SIT_ATTR_6RD_RELAY_PREFIXLEN; + sit->ip6rd_relay_prefixlen = prefixlen; + return 0; +} + +/** + * Get ip6rd relay prefix length + * @arg link Link object + * @arg prefixlen Output pointer for the prefix length + * + * @return 0 on success or an error code. If the property is unset, + * this call fails. + */ +int rtnl_link_sit_get_ip6rd_relay_prefixlen(struct rtnl_link *link, uint16_t *prefixlen) +{ + IS_SIT_LINK_ASSERT(link, sit); + + if (!(sit->sit_mask & SIT_ATTR_6RD_RELAY_PREFIX)) + return -NLE_NOATTR; + + if (prefixlen) + *prefixlen = sit->ip6rd_relay_prefixlen; + return 0; +} + static void __init sit_init(void) { rtnl_link_register_info(&sit_info_ops); |