summaryrefslogtreecommitdiff
path: root/lib/route/link/sit.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/route/link/sit.c')
-rw-r--r--lib/route/link/sit.c323
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);