summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVolodymyr Bendiuga <volodymyr.bendiuga@westermo.se>2018-05-04 09:13:10 (GMT)
committerThomas Haller <thaller@redhat.com>2018-10-10 09:12:08 (GMT)
commitb004e4006374c9f0311461010c9082411c6ef563 (patch)
tree64a3c2e6816faeba71d1e2f17f1ee27eb70c7919
parent07fa87ba90758355781557ad8c4d1f680312ca45 (diff)
downloadlibnl-b004e4006374c9f0311461010c9082411c6ef563.zip
libnl-b004e4006374c9f0311461010c9082411c6ef563.tar.gz
libnl-b004e4006374c9f0311461010c9082411c6ef563.tar.bz2
route:act: add vlan action
For more information please see: http://man7.org/linux/man-pages/man8/tc-vlan.8.html Signed-off-by: Volodymyr Bendiuga <volodymyr.bendiuga@westermo.se>
-rw-r--r--Makefile.am2
-rw-r--r--include/netlink-private/types.h10
-rw-r--r--include/netlink/route/act/vlan.h39
-rw-r--r--lib/route/act/vlan.c416
-rw-r--r--libnl-route-3.sym10
5 files changed, 477 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index a6a605b..2c01e98 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -121,6 +121,7 @@ libnlinclude_netlink_route_act_HEADERS = \
include/netlink/route/act/gact.h \
include/netlink/route/act/mirred.h \
include/netlink/route/act/skbedit.h \
+ include/netlink/route/act/vlan.h \
$(NULL)
libnlinclude_netlink_route_clsdir = $(libnlincludedir)/netlink/route/cls
libnlinclude_netlink_route_cls_HEADERS = \
@@ -370,6 +371,7 @@ lib_libnl_route_3_la_SOURCES = \
lib/route/act/gact.c \
lib/route/act/mirred.c \
lib/route/act/skbedit.c \
+ lib/route/act/vlan.c \
lib/route/addr.c \
lib/route/class.c \
lib/route/classid.c \
diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h
index f94a927..6cd797d 100644
--- a/include/netlink-private/types.h
+++ b/include/netlink-private/types.h
@@ -30,6 +30,7 @@
#include <linux/tc_act/tc_mirred.h>
#include <linux/tc_act/tc_skbedit.h>
#include <linux/tc_act/tc_gact.h>
+#include <linux/tc_act/tc_vlan.h>
#include <linux/sock_diag.h>
#include <linux/fib_rules.h>
@@ -1327,4 +1328,13 @@ struct xfrmnl_sp {
struct xfrmnl_mark mark;
};
+struct rtnl_vlan
+{
+ struct tc_vlan v_parm;
+ uint16_t v_vid;
+ uint16_t v_proto;
+ uint8_t v_prio;
+ uint32_t v_flags;
+};
+
#endif
diff --git a/include/netlink/route/act/vlan.h b/include/netlink/route/act/vlan.h
new file mode 100644
index 0000000..47fc7dc
--- /dev/null
+++ b/include/netlink/route/act/vlan.h
@@ -0,0 +1,39 @@
+/*
+ * netlink/route/act/vlan.h vlan action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+#ifndef NETLINK_VLAN_H_
+#define NETLINK_VLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/cache.h>
+#include <netlink/route/action.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_vlan_set_mode(struct rtnl_act *act, int mode);
+extern int rtnl_vlan_get_mode(struct rtnl_act *act);
+extern int rtnl_vlan_set_action(struct rtnl_act *act, int action);
+extern int rtnl_vlan_get_action(struct rtnl_act *act);
+extern int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol);
+extern uint16_t rtnl_vlan_get_protocol(struct rtnl_act *act);
+extern int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid);
+extern uint16_t rtnl_vlan_get_vlan_id(struct rtnl_act *act);
+extern int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio);
+extern uint8_t rtnl_vlan_get_vlan_prio(struct rtnl_act *act);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NETLINK_VLAN_H */
diff --git a/lib/route/act/vlan.c b/lib/route/act/vlan.c
new file mode 100644
index 0000000..e570ae3
--- /dev/null
+++ b/lib/route/act/vlan.c
@@ -0,0 +1,416 @@
+/*
+ * lib/route/act/vlan.c vlan action
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
+ */
+
+/**
+ * @ingroup act
+ * @defgroup act_vlan VLAN Manipulation
+ *
+ * @{
+ */
+
+#include <netlink-private/netlink.h>
+#include <netlink-private/tc.h>
+#include <netlink/netlink.h>
+#include <netlink/attr.h>
+#include <netlink/utils.h>
+#include <netlink-private/route/tc-api.h>
+#include <netlink/route/act/vlan.h>
+
+
+#define VLAN_F_VID 1 << 0
+#define VLAN_F_PROTO 1 << 1
+#define VLAN_F_PRIO 1 << 2
+#define VLAN_F_ACT 1 << 3
+#define VLAN_F_MODE 1 << 4
+
+static struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
+ [TCA_VLAN_PARMS] = { .minlen = sizeof(struct tc_vlan) },
+ [TCA_VLAN_PUSH_VLAN_ID] = { .type = NLA_U16 },
+ [TCA_VLAN_PUSH_VLAN_PROTOCOL] = { .type = NLA_U16 },
+ [TCA_VLAN_PUSH_VLAN_PRIORITY] = { .type = NLA_U8 },
+};
+
+static int vlan_msg_parser(struct rtnl_tc *tc, void *data)
+{
+ struct rtnl_vlan *v = data;
+ struct nlattr *tb[TCA_VLAN_MAX + 1];
+ int err;
+
+ err = tca_parse(tb, TCA_VLAN_MAX, tc, vlan_policy);
+ if (err < 0)
+ return err;
+
+ v->v_flags = 0;
+ if (!tb[TCA_VLAN_PARMS])
+ return -NLE_MISSING_ATTR;
+ else {
+ nla_memcpy(&v->v_parm, tb[TCA_VLAN_PARMS], sizeof(v->v_parm));
+ v->v_flags |= VLAN_F_ACT;
+ v->v_flags |= VLAN_F_MODE;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
+ v->v_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
+ v->v_flags |= VLAN_F_VID;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
+ v->v_proto = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
+ v->v_flags |= VLAN_F_PROTO;
+ }
+
+ if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
+ v->v_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
+ v->v_flags |= VLAN_F_PRIO;
+ }
+
+ return 0;
+}
+
+static int vlan_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return 0;
+ if (!(v->v_flags & VLAN_F_MODE))
+ return -NLE_MISSING_ATTR;
+
+ NLA_PUT(msg, TCA_VLAN_PARMS, sizeof(v->v_parm), &v->v_parm);
+
+ /* vid is required for PUSH & MODIFY modes */
+ if ((v->v_parm.v_action != TCA_VLAN_ACT_POP) && !(v->v_flags & VLAN_F_VID))
+ return -NLE_MISSING_ATTR;
+
+ if (v->v_flags & VLAN_F_VID)
+ NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_ID, v->v_vid);
+
+ if (v->v_flags & VLAN_F_PROTO)
+ NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_PROTOCOL, v->v_proto);
+
+ if (v->v_flags & VLAN_F_PRIO)
+ NLA_PUT_U8(msg, TCA_VLAN_PUSH_VLAN_PRIORITY, v->v_prio);
+
+ return 0;
+
+ nla_put_failure:
+ return -NLE_NOMEM;
+}
+
+static void vlan_free_data(struct rtnl_tc *tc, void *data)
+{
+}
+
+static int vlan_clone(void *_dst, void *_src)
+{
+ struct rtnl_vlan *dst = _dst, *src = _src;
+
+ memcpy(&dst->v_parm, &src->v_parm, sizeof(src->v_parm));
+ return 0;
+}
+
+static void vlan_dump_line(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return;
+
+ if (!(v->v_flags & VLAN_F_ACT))
+ return;
+
+ if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_GOTO_CHAIN))
+ nl_dump(p, " goto chain %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
+
+ if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_JUMP))
+ nl_dump(p, " jump %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
+
+ switch(v->v_parm.action){
+ case TC_ACT_UNSPEC:
+ nl_dump(p, " unspecified");
+ break;
+ case TC_ACT_PIPE:
+ nl_dump(p, " pipe");
+ break;
+ case TC_ACT_STOLEN:
+ nl_dump(p, " stolen");
+ break;
+ case TC_ACT_SHOT:
+ nl_dump(p, " shot");
+ break;
+ case TC_ACT_QUEUED:
+ nl_dump(p, " queued");
+ break;
+ case TC_ACT_REPEAT:
+ nl_dump(p, " repeat");
+ break;
+ }
+}
+
+static void vlan_dump_details(struct rtnl_tc *tc, void *data,
+ struct nl_dump_params *p)
+{
+ struct rtnl_vlan *v = data;
+
+ if (!v)
+ return;
+
+ if (v->v_flags & VLAN_F_MODE) {
+ switch (v->v_parm.v_action) {
+ case TCA_VLAN_ACT_POP:
+ nl_dump(p, " mode POP");
+ break;
+ case TCA_VLAN_ACT_PUSH:
+ nl_dump(p, " mode PUSH");
+ break;
+ case TCA_VLAN_ACT_MODIFY:
+ nl_dump(p, " mode MODIFY");
+ break;
+ }
+ }
+
+ if (v->v_flags & VLAN_F_VID)
+ nl_dump(p, " vlan id %u", v->v_vid);
+
+ if (v->v_flags & VLAN_F_PRIO)
+ nl_dump(p, " priority %u", v->v_prio);
+
+ if (v->v_flags & VLAN_F_PROTO)
+ nl_dump(p, " protocol %u", v->v_proto);
+}
+
+/**
+ * @name Attribute Modifications
+ * @{
+ */
+
+/**
+ * Set vlan mode
+ * @arg act vlan action
+ * @arg mode one of (TCA_VLAN_ACT_*: POP, PUSH, MODIFY)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_mode(struct rtnl_act *act, int mode)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (mode > TCA_VLAN_ACT_MODIFY)
+ return -NLE_RANGE;
+
+ v->v_parm.v_action = mode;
+ v->v_flags |= VLAN_F_MODE;
+
+ return 0;
+}
+
+/**
+ * Get vlan mode
+ * @arg act vlan action
+ * @return vlan mode on success or a negative error code.
+*/
+int rtnl_vlan_get_mode(struct rtnl_act *act)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (!(v->v_flags & VLAN_F_MODE))
+ return -NLE_MISSING_ATTR;
+
+ return v->v_parm.v_action;
+}
+
+/**
+ * Set general action
+ * @arg act vlan action
+ * @arg action one of (TCA_ACT_*: PIPE, SHOT, GOTO_CHAIN, etc)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_action(struct rtnl_act *act, int action)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ v->v_parm.action = action;
+ v->v_flags |= VLAN_F_ACT;
+
+ return 0;
+}
+
+/**
+ * Get general action
+ * @arg act vlan action
+ * @return general action on success or a negative error code.
+*/
+int rtnl_vlan_get_action(struct rtnl_act *act)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (!(v->v_flags & VLAN_F_ACT))
+ return -NLE_MISSING_ATTR;
+
+ return v->v_parm.action;
+}
+
+/**
+ * Set protocol
+ * @arg act vlan action
+ * @arg protocol one of (ETH_P_8021Q || ETH_P_8021AD)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ v->v_proto = protocol;
+ v->v_flags |= VLAN_F_PROTO;
+
+ return 0;
+}
+
+/**
+ * Get protocol
+ * @arg act vlan action
+ * @return protocol on success or a negative error code.
+*/
+uint16_t rtnl_vlan_get_protocol(struct rtnl_act *act)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (!(v->v_flags & VLAN_F_PROTO))
+ return -NLE_MISSING_ATTR;
+
+ return v->v_proto;
+}
+
+/**
+ * Set vlan id
+ * @arg act vlan action
+ * @arg vid vlan id
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (vid > 4095)
+ return -NLE_RANGE;
+
+ v->v_vid = vid;
+ v->v_flags |= VLAN_F_VID;
+
+ return 0;
+}
+
+/**
+ * Get vlan id
+ * @arg act vlan action
+ * @return vlan id on success or a negative error code.
+*/
+uint16_t rtnl_vlan_get_vlan_id(struct rtnl_act *act)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (!(v->v_flags & VLAN_F_VID))
+ return -NLE_MISSING_ATTR;
+
+ return v->v_vid;
+}
+
+/**
+ * Set vlan prio
+ * @arg act vlan action
+ * @arg prio vlan priority (0 - 7)
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (prio > 7)
+ return -NLE_RANGE;
+
+ v->v_prio = prio;
+ v->v_flags |= VLAN_F_PRIO;
+
+ return 0;
+}
+
+/**
+ * Get vlan prio
+ * @arg act vlan action
+ * @return vlan prio on success or a negative error code.
+*/
+uint8_t rtnl_vlan_get_vlan_prio(struct rtnl_act *act)
+{
+ struct rtnl_vlan *v;
+
+ if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
+ return -NLE_NOMEM;
+
+ if (!(v->v_flags & VLAN_F_PRIO))
+ return -NLE_MISSING_ATTR;
+
+ return v->v_prio;
+}
+
+/** @} */
+
+static struct rtnl_tc_ops vlan_ops = {
+ .to_kind = "vlan",
+ .to_type = RTNL_TC_TYPE_ACT,
+ .to_size = sizeof(struct rtnl_vlan),
+ .to_msg_parser = vlan_msg_parser,
+ .to_free_data = vlan_free_data,
+ .to_clone = vlan_clone,
+ .to_msg_fill = vlan_msg_fill,
+ .to_dump = {
+ [NL_DUMP_LINE] = vlan_dump_line,
+ [NL_DUMP_DETAILS] = vlan_dump_details,
+ },
+};
+
+static void __init vlan_init(void)
+{
+ rtnl_tc_register(&vlan_ops);
+}
+
+static void __exit vlan_exit(void)
+{
+ rtnl_tc_unregister(&vlan_ops);
+}
+
+/** @} */
diff --git a/libnl-route-3.sym b/libnl-route-3.sym
index d161ebb..02aae7a 100644
--- a/libnl-route-3.sym
+++ b/libnl-route-3.sym
@@ -1127,4 +1127,14 @@ global:
rtnl_rule_set_sport_range;
rtnl_tc_get_chain;
rtnl_tc_set_chain;
+ rtnl_vlan_get_action;
+ rtnl_vlan_get_mode;
+ rtnl_vlan_get_protocol;
+ rtnl_vlan_get_vlan_id;
+ rtnl_vlan_get_vlan_prio;
+ rtnl_vlan_set_action;
+ rtnl_vlan_set_mode;
+ rtnl_vlan_set_protocol;
+ rtnl_vlan_set_vlan_id;
+ rtnl_vlan_set_vlan_prio;
} libnl_3_4;