1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2013 Cong Wang <[email protected]>
4 */
5
6 /**
7 * @ingroup act
8 * @defgroup act_mirred Mirror and Redirect
9 *
10 * @{
11 */
12
13 #include "nl-default.h"
14
15 #include <netlink/netlink.h>
16 #include <netlink/attr.h>
17 #include <netlink/utils.h>
18 #include <netlink/route/act/mirred.h>
19
20 #include "tc-api.h"
21
22 struct rtnl_mirred {
23 struct tc_mirred m_parm;
24 };
25
26 static struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = {
27 [TCA_MIRRED_PARMS] = { .minlen = sizeof(struct tc_mirred) },
28 };
29
mirred_msg_parser(struct rtnl_tc * tc,void * data)30 static int mirred_msg_parser(struct rtnl_tc *tc, void *data)
31 {
32 struct rtnl_mirred *u = data;
33 struct nlattr *tb[TCA_MIRRED_MAX + 1];
34 int err;
35
36 err = tca_parse(tb, TCA_MIRRED_MAX, tc, mirred_policy);
37 if (err < 0)
38 return err;
39
40 if (!tb[TCA_MIRRED_PARMS])
41 return -NLE_MISSING_ATTR;
42
43 nla_memcpy(&u->m_parm, tb[TCA_MIRRED_PARMS], sizeof(u->m_parm));
44 return 0;
45 }
46
mirred_free_data(struct rtnl_tc * tc,void * data)47 static void mirred_free_data(struct rtnl_tc *tc, void *data)
48 {
49 }
50
mirred_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)51 static void mirred_dump_line(struct rtnl_tc *tc, void *data,
52 struct nl_dump_params *p)
53 {
54 struct rtnl_mirred *u = data;
55 if (!u)
56 return;
57
58 nl_dump(p, " index %u", u->m_parm.ifindex);
59
60 if (u->m_parm.eaction == TCA_EGRESS_MIRROR)
61 nl_dump(p, " egress mirror");
62 else if (u->m_parm.eaction == TCA_EGRESS_REDIR)
63 nl_dump(p, " egress redirect");
64
65 switch(u->m_parm.action) {
66 case TC_ACT_UNSPEC:
67 nl_dump(p, " unspecified");
68 break;
69 case TC_ACT_PIPE:
70 nl_dump(p, " pipe");
71 break;
72 case TC_ACT_STOLEN:
73 nl_dump(p, " stolen");
74 break;
75 case TC_ACT_SHOT:
76 nl_dump(p, " shot");
77 break;
78 case TC_ACT_QUEUED:
79 nl_dump(p, " queued");
80 break;
81 case TC_ACT_REPEAT:
82 nl_dump(p, " repeat");
83 break;
84 }
85 }
86
mirred_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)87 static void mirred_dump_details(struct rtnl_tc *tc, void *data,
88 struct nl_dump_params *p)
89 {
90 }
91
mirred_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)92 static void mirred_dump_stats(struct rtnl_tc *tc, void *data,
93 struct nl_dump_params *p)
94 {
95 struct rtnl_mirred *u = data;
96
97 if (!u)
98 return;
99 /* TODO */
100 }
101
102
mirred_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)103 static int mirred_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
104 {
105 struct rtnl_mirred *u = data;
106
107 if (!u)
108 return 0;
109
110 NLA_PUT(msg, TCA_MIRRED_PARMS, sizeof(u->m_parm), &u->m_parm);
111 return 0;
112
113 nla_put_failure:
114 return -NLE_NOMEM;
115 }
116
117 /**
118 * @name Attribute Modifications
119 * @{
120 */
121
rtnl_mirred_set_action(struct rtnl_act * act,int action)122 int rtnl_mirred_set_action(struct rtnl_act *act, int action)
123 {
124 struct rtnl_mirred *u;
125
126 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
127 return -NLE_NOMEM;
128
129 if (action > TCA_INGRESS_MIRROR || action < TCA_EGRESS_REDIR)
130 return -NLE_INVAL;
131
132 switch (action) {
133 case TCA_EGRESS_MIRROR:
134 case TCA_EGRESS_REDIR:
135 u->m_parm.eaction = action;
136 break;
137 case TCA_INGRESS_REDIR:
138 case TCA_INGRESS_MIRROR:
139 default:
140 return NLE_OPNOTSUPP;
141 }
142 return 0;
143 }
144
rtnl_mirred_get_action(struct rtnl_act * act)145 int rtnl_mirred_get_action(struct rtnl_act *act)
146 {
147 struct rtnl_mirred *u;
148
149 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
150 return -NLE_NOMEM;
151 return u->m_parm.eaction;
152 }
153
rtnl_mirred_set_ifindex(struct rtnl_act * act,uint32_t ifindex)154 int rtnl_mirred_set_ifindex(struct rtnl_act *act, uint32_t ifindex)
155 {
156 struct rtnl_mirred *u;
157
158 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
159 return -NLE_NOMEM;
160
161 u->m_parm.ifindex = ifindex;
162 return 0;
163 }
164
rtnl_mirred_get_ifindex(struct rtnl_act * act)165 uint32_t rtnl_mirred_get_ifindex(struct rtnl_act *act)
166 {
167 struct rtnl_mirred *u;
168
169 if ((u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
170 return u->m_parm.ifindex;
171 return 0;
172 }
173
rtnl_mirred_set_policy(struct rtnl_act * act,int policy)174 int rtnl_mirred_set_policy(struct rtnl_act *act, int policy)
175 {
176 struct rtnl_mirred *u;
177
178 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
179 return -NLE_NOMEM;
180
181 u->m_parm.action = policy;
182
183 return 0;
184 }
185
rtnl_mirred_get_policy(struct rtnl_act * act)186 int rtnl_mirred_get_policy(struct rtnl_act *act)
187 {
188 struct rtnl_mirred *u;
189
190 if (!(u = (struct rtnl_mirred *) rtnl_tc_data(TC_CAST(act))))
191 return -NLE_NOMEM;
192 return u->m_parm.action;
193 }
194
195 /** @} */
196
197 static struct rtnl_tc_ops mirred_ops = {
198 .to_kind = "mirred",
199 .to_type = RTNL_TC_TYPE_ACT,
200 .to_size = sizeof(struct rtnl_mirred),
201 .to_msg_parser = mirred_msg_parser,
202 .to_free_data = mirred_free_data,
203 .to_clone = NULL,
204 .to_msg_fill = mirred_msg_fill,
205 .to_dump = {
206 [NL_DUMP_LINE] = mirred_dump_line,
207 [NL_DUMP_DETAILS] = mirred_dump_details,
208 [NL_DUMP_STATS] = mirred_dump_stats,
209 },
210 };
211
mirred_init(void)212 static void _nl_init mirred_init(void)
213 {
214 rtnl_tc_register(&mirred_ops);
215 }
216
mirred_exit(void)217 static void _nl_exit mirred_exit(void)
218 {
219 rtnl_tc_unregister(&mirred_ops);
220 }
221
222 /** @} */
223