1 /*
2 Copyright (c) 2013, The Linux Foundation. All rights reserved.
3
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*!
30 @file
31 IPACM_Routing.cpp
32
33 @brief
34 This file implements the IPACM routing functionality.
35
36 @Author
37
38 */
39
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include "IPACM_Routing.h"
47 #include <IPACM_Log.h>
48
49 const char *IPACM_Routing::DEVICE_NAME = "/dev/ipa";
50
IPACM_Routing()51 IPACM_Routing::IPACM_Routing()
52 {
53 m_fd = open(DEVICE_NAME, O_RDWR);
54 if (0 == m_fd)
55 {
56 IPACMERR("Failed opening %s.\n", DEVICE_NAME);
57 }
58 }
59
~IPACM_Routing()60 IPACM_Routing::~IPACM_Routing()
61 {
62 close(m_fd);
63 }
64
DeviceNodeIsOpened()65 bool IPACM_Routing::DeviceNodeIsOpened()
66 {
67 int res = fcntl(m_fd, F_GETFL);
68
69 if (m_fd > 0 && res >= 0) return true;
70 else return false;
71
72 }
73
AddRoutingRule(struct ipa_ioc_add_rt_rule * ruleTable)74 bool IPACM_Routing::AddRoutingRule(struct ipa_ioc_add_rt_rule *ruleTable)
75 {
76 int retval = 0, cnt=0;
77 bool isInvalid = false;
78
79 if (!DeviceNodeIsOpened())
80 {
81 IPACMERR("Device is not opened\n");
82 return false;
83 }
84
85 for(cnt=0; cnt<ruleTable->num_rules; cnt++)
86 {
87 if(ruleTable->rules[cnt].rule.dst > IPA_CLIENT_MAX)
88 {
89 IPACMERR("Invalid dst pipe, Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
90 isInvalid = true;
91 }
92 }
93
94 if(isInvalid)
95 {
96 return false;
97 }
98
99 retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE, ruleTable);
100 if (retval)
101 {
102 IPACMERR("Failed adding routing rule %p\n", ruleTable);
103 return false;
104 }
105
106 for(cnt=0; cnt<ruleTable->num_rules; cnt++)
107 {
108 IPACMDBG("Rule:%d dst_pipe:%d\n", cnt, ruleTable->rules[cnt].rule.dst);
109 }
110
111 IPACMDBG_H("Added routing rule %p\n", ruleTable);
112 return true;
113 }
114
115 #ifdef IPA_IOCTL_SET_FNR_COUNTER_INFO
AddRoutingRule_hw_index(struct ipa_ioc_add_rt_rule * ruleTable,int hw_counter_index)116 bool IPACM_Routing::AddRoutingRule_hw_index(struct ipa_ioc_add_rt_rule *ruleTable, int hw_counter_index)
117 {
118 int retval = 0, cnt = 0, len = 0;
119 struct ipa_ioc_add_rt_rule_v2 *ruleTable_v2;
120 struct ipa_rt_rule_add_v2 rt_rule_entry;
121 bool ret = true;
122
123 IPACMDBG("Printing routing add attributes\n");
124 IPACMDBG("ip type: %d\n", ruleTable->ip);
125 IPACMDBG("rt tbl type: %s\n", ruleTable->rt_tbl_name);
126 IPACMDBG("Number of rules: %d\n", ruleTable->num_rules);
127 IPACMDBG("commit value: %d\n", ruleTable->commit);
128
129 /* change to v2 format*/
130 len = sizeof(struct ipa_ioc_add_rt_rule_v2);
131 ruleTable_v2 = (struct ipa_ioc_add_rt_rule_v2*)malloc(len);
132 if (ruleTable_v2 == NULL)
133 {
134 IPACMERR("Error Locate ipa_ioc_add_rt_rule_v2 memory...\n");
135 return false;
136 }
137 memset(ruleTable_v2, 0, len);
138 ruleTable_v2->rules = (uint64_t)calloc(ruleTable->num_rules, sizeof(struct ipa_rt_rule_add_v2));
139 if (!ruleTable_v2->rules) {
140 IPACMERR("Failed to allocate memory for routing rules\n");
141 ret = false;
142 goto fail_tbl;
143 }
144
145 ruleTable_v2->commit = ruleTable->commit;
146 ruleTable_v2->ip = ruleTable->ip;
147 ruleTable_v2->num_rules = ruleTable->num_rules;
148 ruleTable_v2->rule_add_size = sizeof(struct ipa_rt_rule_add_v2);
149 memcpy(ruleTable_v2->rt_tbl_name,
150 ruleTable->rt_tbl_name,
151 sizeof(ruleTable_v2->rt_tbl_name));
152
153 for (cnt=0; cnt < ruleTable->num_rules; cnt++)
154 {
155 memset(&rt_rule_entry, 0, sizeof(struct ipa_rt_rule_add_v2));
156 rt_rule_entry.at_rear = ruleTable->rules[cnt].at_rear;
157 rt_rule_entry.rule.dst = ruleTable->rules[cnt].rule.dst;
158 rt_rule_entry.rule.hdr_hdl = ruleTable->rules[cnt].rule.hdr_hdl;
159 rt_rule_entry.rule.hdr_proc_ctx_hdl = ruleTable->rules[cnt].rule.hdr_proc_ctx_hdl;
160 rt_rule_entry.rule.max_prio = ruleTable->rules[cnt].rule.max_prio;
161 rt_rule_entry.rule.hashable = ruleTable->rules[cnt].rule.hashable;
162 rt_rule_entry.rule.retain_hdr = ruleTable->rules[cnt].rule.retain_hdr;
163 rt_rule_entry.rule.coalesce = ruleTable->rules[cnt].rule.coalesce;
164 memcpy(&rt_rule_entry.rule.attrib,
165 &ruleTable->rules[cnt].rule.attrib,
166 sizeof(rt_rule_entry.rule.attrib));
167 IPACMDBG("RT rule:%d attrib mask: 0x%x\n", cnt,
168 ruleTable->rules[cnt].rule.attrib.attrib_mask);
169 /* 0 means disable hw-counter-sats */
170 if (hw_counter_index != 0)
171 {
172 rt_rule_entry.rule.enable_stats = 1;
173 rt_rule_entry.rule.cnt_idx = hw_counter_index;
174 }
175
176 /* copy to v2 table*/
177 memcpy((void *)(ruleTable_v2->rules + (cnt * sizeof(struct ipa_rt_rule_add_v2))),
178 &rt_rule_entry, sizeof(rt_rule_entry));
179 }
180
181 retval = ioctl(m_fd, IPA_IOC_ADD_RT_RULE_V2, ruleTable_v2);
182 if (retval != 0)
183 {
184 IPACMERR("Failed adding Routing rule %pK\n", ruleTable_v2);
185 PERROR("unable to add routing rule:");
186
187 for (int cnt = 0; cnt < ruleTable_v2->num_rules; cnt++)
188 {
189 if (((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
190 {
191 IPACMERR("Adding Routing rule:%d failed with status:%d\n",
192 cnt, ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status);
193 }
194 }
195 ret = false;
196 goto fail_rule;
197 }
198
199 /* copy results from v2 to v1 format */
200 for (int cnt = 0; cnt < ruleTable->num_rules; cnt++)
201 {
202 /* copy status to v1 format */
203 ruleTable->rules[cnt].status = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status;
204 ruleTable->rules[cnt].rt_rule_hdl = ((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].rt_rule_hdl;
205
206 if(((struct ipa_rt_rule_add_v2 *)ruleTable_v2->rules)[cnt].status != 0)
207 {
208 IPACMERR("Adding Routing rule:%d failed with status:%d\n",
209 cnt, ((struct ipa_rt_rule_add_v2 *) ruleTable_v2->rules)[cnt].status);
210 }
211 }
212 IPACMDBG("Added Routing rule %pK\n", ruleTable_v2);
213 fail_rule:
214 if((void *)ruleTable_v2->rules != NULL)
215 free((void *)ruleTable_v2->rules);
216 fail_tbl:
217 if (ruleTable_v2 != NULL)
218 free(ruleTable_v2);
219 return ret;
220 }
221 #endif //IPA_IOCTL_SET_FNR_COUNTER_INFO
222
223
DeleteRoutingRule(struct ipa_ioc_del_rt_rule * ruleTable)224 bool IPACM_Routing::DeleteRoutingRule(struct ipa_ioc_del_rt_rule *ruleTable)
225 {
226 int retval = 0;
227
228 if (!DeviceNodeIsOpened()) return false;
229
230 retval = ioctl(m_fd, IPA_IOC_DEL_RT_RULE, ruleTable);
231 if (retval)
232 {
233 IPACMERR("Failed deleting routing rule table %p\n", ruleTable);
234 return false;
235 }
236
237 IPACMDBG_H("Deleted routing rule %p\n", ruleTable);
238 return true;
239 }
240
Commit(enum ipa_ip_type ip)241 bool IPACM_Routing::Commit(enum ipa_ip_type ip)
242 {
243 int retval = 0;
244
245 if (!DeviceNodeIsOpened()) return false;
246
247 retval = ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
248 if (retval)
249 {
250 IPACMERR("Failed commiting routing rules.\n");
251 return false;
252 }
253
254 IPACMDBG_H("Commited routing rules to IPA HW.\n");
255 return true;
256 }
257
Reset(enum ipa_ip_type ip)258 bool IPACM_Routing::Reset(enum ipa_ip_type ip)
259 {
260 int retval = 0;
261
262 if (!DeviceNodeIsOpened()) return false;
263
264 retval = ioctl(m_fd, IPA_IOC_RESET_RT, ip);
265 retval |= ioctl(m_fd, IPA_IOC_COMMIT_RT, ip);
266 if (retval)
267 {
268 IPACMERR("Failed resetting routing block.\n");
269 return false;
270 }
271
272 IPACMDBG_H("Reset command issued to IPA routing block.\n");
273 return true;
274 }
275
GetRoutingTable(struct ipa_ioc_get_rt_tbl * routingTable)276 bool IPACM_Routing::GetRoutingTable(struct ipa_ioc_get_rt_tbl *routingTable)
277 {
278 int retval = 0;
279
280 if (!DeviceNodeIsOpened()) return false;
281
282 retval = ioctl(m_fd, IPA_IOC_GET_RT_TBL, routingTable);
283 if (retval)
284 {
285 IPACMERR("IPA_IOCTL_GET_RT_TBL ioctl failed, routingTable =0x%p, retval=0x%x.\n", routingTable, retval);
286 return false;
287 }
288 IPACMDBG_H("IPA_IOCTL_GET_RT_TBL ioctl issued to IPA routing block.\n");
289 /* put routing table right after successfully get routing table */
290 PutRoutingTable(routingTable->hdl);
291
292 return true;
293 }
294
PutRoutingTable(uint32_t routingTableHandle)295 bool IPACM_Routing::PutRoutingTable(uint32_t routingTableHandle)
296 {
297 int retval = 0;
298
299 if (!DeviceNodeIsOpened()) return false;
300
301 retval = ioctl(m_fd, IPA_IOC_PUT_RT_TBL, routingTableHandle);
302 if (retval)
303 {
304 IPACMERR("IPA_IOCTL_PUT_RT_TBL ioctl failed.\n");
305 return false;
306 }
307
308 IPACMDBG_H("IPA_IOCTL_PUT_RT_TBL ioctl issued to IPA routing block.\n");
309 return true;
310 }
311
DeleteRoutingHdl(uint32_t rt_rule_hdl,ipa_ip_type ip)312 bool IPACM_Routing::DeleteRoutingHdl(uint32_t rt_rule_hdl, ipa_ip_type ip)
313 {
314 const uint8_t NUM_RULES = 1;
315 struct ipa_ioc_del_rt_rule *rt_rule;
316 struct ipa_rt_rule_del *rt_rule_entry;
317 bool res = true;
318 int len = 0;
319
320 if (rt_rule_hdl == 0)
321 {
322 IPACMERR(" No route handle passed. Ignoring it\n");
323 return res;
324 }
325
326 len = (sizeof(struct ipa_ioc_del_rt_rule)) + (NUM_RULES * sizeof(struct ipa_rt_rule_del));
327 rt_rule = (struct ipa_ioc_del_rt_rule *)malloc(len);
328 if (rt_rule == NULL)
329 {
330 IPACMERR("unable to allocate memory for del route rule\n");
331 return false;
332 }
333
334 memset(rt_rule, 0, len);
335 rt_rule->commit = 1;
336 rt_rule->num_hdls = NUM_RULES;
337 rt_rule->ip = ip;
338
339 rt_rule_entry = &rt_rule->hdl[0];
340 rt_rule_entry->status = -1;
341 rt_rule_entry->hdl = rt_rule_hdl;
342
343 IPACMDBG_H("Deleting Route hdl:(0x%x) with ip type: %d\n", rt_rule_entry->hdl, ip);
344 if ((false == DeleteRoutingRule(rt_rule)) ||
345 (rt_rule_entry->status))
346 {
347 PERROR("Routing rule deletion failed!\n");
348 goto fail;
349 res = false;
350 }
351
352 fail:
353 free(rt_rule);
354
355 return res;
356 }
357
ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule * mdfyRules)358 bool IPACM_Routing::ModifyRoutingRule(struct ipa_ioc_mdfy_rt_rule *mdfyRules)
359 {
360 int retval = 0, cnt;
361
362 if (!DeviceNodeIsOpened())
363 {
364 IPACMERR("Device is not opened\n");
365 return false;
366 }
367
368 retval = ioctl(m_fd, IPA_IOC_MDFY_RT_RULE, mdfyRules);
369 if (retval)
370 {
371 IPACMERR("Failed modifying routing rules %p\n", mdfyRules);
372 return false;
373 }
374
375 for(cnt=0; cnt<mdfyRules->num_rules; cnt++)
376 {
377 if(mdfyRules->rules[cnt].status != 0)
378 {
379 IPACMERR("Unable to modify rule: %d\n", cnt);
380 }
381 }
382
383 IPACMDBG_H("Modified routing rules %p\n", mdfyRules);
384 return true;
385 }
386