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