]>
Commit | Line | Data |
---|---|---|
942bf97b | 1 | /* Zebra Policy Based Routing (PBR) main handling. |
2 | * Copyright (C) 2018 Cumulus Networks, Inc. | |
3 | * | |
4 | * This file is part of FRR. | |
5 | * | |
6 | * FRR is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the | |
8 | * Free Software Foundation; either version 2, or (at your option) any | |
9 | * later version. | |
10 | * | |
11 | * FRR is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with FRR; see the file COPYING. If not, write to the Free | |
18 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
19 | * 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #include <zebra.h> | |
23 | ||
43fe6a2a DS |
24 | #include <jhash.h> |
25 | #include <hash.h> | |
26 | ||
942bf97b | 27 | #include "zebra/zebra_pbr.h" |
28 | #include "zebra/rt.h" | |
29 | ||
30 | /* definitions */ | |
31 | ||
32 | /* static function declarations */ | |
33 | ||
34 | /* Private functions */ | |
35 | ||
36 | /* Public functions */ | |
43fe6a2a | 37 | void zebra_pbr_rules_free(void *arg) |
1fbfe5a5 | 38 | { |
43fe6a2a DS |
39 | struct zebra_pbr_rule *rule; |
40 | ||
41 | rule = (struct zebra_pbr_rule *)arg; | |
42 | ||
a0321978 | 43 | kernel_del_pbr_rule(rule); |
43fe6a2a DS |
44 | XFREE(MTYPE_TMP, rule); |
45 | } | |
46 | ||
47 | uint32_t zebra_pbr_rules_hash_key(void *arg) | |
48 | { | |
49 | struct zebra_pbr_rule *rule; | |
50 | uint32_t key; | |
51 | ||
52 | rule = (struct zebra_pbr_rule *)arg; | |
53 | key = jhash_3words(rule->seq, rule->priority, rule->action.table, | |
54 | prefix_hash_key(&rule->filter.src_ip)); | |
a0321978 DS |
55 | if (rule->ifp) |
56 | key = jhash_1word(rule->ifp->ifindex, key); | |
57 | else | |
58 | key = jhash_1word(0, key); | |
59 | ||
43fe6a2a | 60 | return jhash_3words(rule->filter.src_port, rule->filter.dst_port, |
b6c5d343 DS |
61 | prefix_hash_key(&rule->filter.dst_ip), |
62 | jhash_1word(rule->unique, key)); | |
43fe6a2a DS |
63 | } |
64 | ||
65 | int zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) | |
66 | { | |
67 | const struct zebra_pbr_rule *r1, *r2; | |
68 | ||
69 | r1 = (const struct zebra_pbr_rule *)arg1; | |
70 | r2 = (const struct zebra_pbr_rule *)arg2; | |
71 | ||
72 | if (r1->seq != r2->seq) | |
73 | return 0; | |
74 | ||
75 | if (r1->priority != r2->priority) | |
76 | return 0; | |
77 | ||
b6c5d343 DS |
78 | if (r1->unique != r2->unique) |
79 | return 0; | |
80 | ||
43fe6a2a DS |
81 | if (r1->action.table != r2->action.table) |
82 | return 0; | |
83 | ||
84 | if (r1->filter.src_port != r2->filter.src_port) | |
85 | return 0; | |
86 | ||
87 | if (r1->filter.dst_port != r2->filter.dst_port) | |
88 | return 0; | |
89 | ||
90 | if (!prefix_same(&r1->filter.src_ip, &r2->filter.src_ip)) | |
91 | return 0; | |
92 | ||
93 | if (!prefix_same(&r1->filter.dst_ip, &r2->filter.dst_ip)) | |
94 | return 0; | |
95 | ||
a0321978 DS |
96 | if (r1->ifp != r2->ifp) |
97 | return 0; | |
98 | ||
43fe6a2a DS |
99 | return 1; |
100 | } | |
101 | ||
8c3cd6c6 DS |
102 | struct pbr_unique_lookup { |
103 | struct zebra_pbr_rule *rule; | |
104 | uint32_t unique; | |
105 | }; | |
106 | ||
107 | static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) | |
108 | { | |
109 | struct pbr_unique_lookup *pul = data; | |
110 | struct zebra_pbr_rule *rule = b->data; | |
111 | ||
112 | if (pul->unique == rule->unique) { | |
113 | pul->rule = rule; | |
114 | return HASHWALK_ABORT; | |
115 | } | |
116 | ||
117 | return HASHWALK_CONTINUE; | |
118 | } | |
119 | ||
120 | static struct zebra_pbr_rule *pbr_rule_lookup_unique(struct zebra_ns *zns, | |
121 | uint32_t unique) | |
122 | { | |
123 | struct pbr_unique_lookup pul; | |
124 | ||
125 | pul.unique = unique; | |
126 | pul.rule = NULL; | |
127 | hash_walk(zns->rules_hash, &pbr_rule_lookup_unique_walker, &pul); | |
128 | ||
129 | return pul.rule; | |
130 | } | |
131 | ||
7661461a PG |
132 | void zebra_pbr_ipset_free(void *arg) |
133 | { | |
134 | struct zebra_pbr_ipset *ipset; | |
135 | ||
136 | ipset = (struct zebra_pbr_ipset *)arg; | |
137 | ||
138 | XFREE(MTYPE_TMP, ipset); | |
139 | } | |
140 | ||
141 | uint32_t zebra_pbr_ipset_hash_key(void *arg) | |
142 | { | |
143 | struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg; | |
144 | uint32_t *pnt = (uint32_t *)ipset->ipset_name; | |
145 | ||
146 | return jhash2(pnt, ZEBRA_IPSET_NAME_SIZE, 0x63ab42de); | |
147 | } | |
148 | ||
149 | int zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) | |
150 | { | |
151 | const struct zebra_pbr_ipset *r1, *r2; | |
152 | ||
153 | r1 = (const struct zebra_pbr_ipset *)arg1; | |
154 | r2 = (const struct zebra_pbr_ipset *)arg2; | |
155 | ||
156 | if (r1->type != r2->type) | |
157 | return 0; | |
158 | if (r1->unique != r2->unique) | |
159 | return 0; | |
160 | if (strncmp(r1->ipset_name, r2->ipset_name, | |
161 | ZEBRA_IPSET_NAME_SIZE)) | |
162 | return 0; | |
163 | return 1; | |
164 | } | |
165 | ||
166 | void zebra_pbr_ipset_entry_free(void *arg) | |
167 | { | |
168 | struct zebra_pbr_ipset_entry *ipset; | |
169 | ||
170 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
171 | ||
172 | XFREE(MTYPE_TMP, ipset); | |
173 | } | |
174 | ||
175 | uint32_t zebra_pbr_ipset_entry_hash_key(void *arg) | |
176 | { | |
177 | struct zebra_pbr_ipset_entry *ipset; | |
178 | uint32_t key; | |
179 | ||
180 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
181 | key = prefix_hash_key(&ipset->src); | |
182 | key = jhash_1word(ipset->unique, key); | |
183 | key = jhash_1word(prefix_hash_key(&ipset->dst), key); | |
184 | ||
185 | return key; | |
186 | } | |
187 | ||
188 | int zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) | |
189 | { | |
190 | const struct zebra_pbr_ipset_entry *r1, *r2; | |
191 | ||
192 | r1 = (const struct zebra_pbr_ipset_entry *)arg1; | |
193 | r2 = (const struct zebra_pbr_ipset_entry *)arg2; | |
194 | ||
195 | if (r1->unique != r2->unique) | |
196 | return 0; | |
197 | ||
198 | if (!prefix_same(&r1->src, &r2->src)) | |
199 | return 0; | |
200 | ||
201 | if (!prefix_same(&r1->dst, &r2->dst)) | |
202 | return 0; | |
203 | ||
204 | return 1; | |
205 | } | |
206 | ||
43fe6a2a DS |
207 | static void *pbr_rule_alloc_intern(void *arg) |
208 | { | |
209 | struct zebra_pbr_rule *zpr; | |
210 | struct zebra_pbr_rule *new; | |
211 | ||
212 | zpr = (struct zebra_pbr_rule *)arg; | |
213 | ||
214 | new = XCALLOC(MTYPE_TMP, sizeof(*new)); | |
215 | ||
216 | memcpy(new, zpr, sizeof(*zpr)); | |
217 | ||
218 | return new; | |
219 | } | |
220 | ||
a0321978 | 221 | void zebra_pbr_add_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
43fe6a2a | 222 | { |
8c3cd6c6 DS |
223 | struct zebra_pbr_rule *unique = |
224 | pbr_rule_lookup_unique(zns, rule->unique); | |
225 | ||
43fe6a2a | 226 | (void)hash_get(zns->rules_hash, rule, pbr_rule_alloc_intern); |
a0321978 | 227 | kernel_add_pbr_rule(rule); |
8c3cd6c6 DS |
228 | |
229 | /* | |
230 | * Rule Replace semantics, if we have an old, install the | |
231 | * new rule, look above, and then delete the old | |
232 | */ | |
233 | if (unique) | |
234 | zebra_pbr_del_rule(zns, unique); | |
1fbfe5a5 DS |
235 | } |
236 | ||
a0321978 | 237 | void zebra_pbr_del_rule(struct zebra_ns *zns, struct zebra_pbr_rule *rule) |
1fbfe5a5 | 238 | { |
43fe6a2a DS |
239 | struct zebra_pbr_rule *lookup; |
240 | ||
241 | lookup = hash_lookup(zns->rules_hash, rule); | |
a0321978 | 242 | kernel_del_pbr_rule(rule); |
43fe6a2a | 243 | |
d5c52f76 DS |
244 | if (lookup) { |
245 | hash_release(zns->rules_hash, lookup); | |
43fe6a2a | 246 | XFREE(MTYPE_TMP, lookup); |
d5c52f76 | 247 | } else |
43fe6a2a DS |
248 | zlog_warn("%s: Rule being deleted we know nothing about", |
249 | __PRETTY_FUNCTION__); | |
1fbfe5a5 DS |
250 | } |
251 | ||
e69aa084 DS |
252 | static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) |
253 | { | |
254 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
255 | struct zebra_pbr_rule *rule = b->data; | |
256 | int *sock = data; | |
257 | ||
258 | if (rule->sock == *sock) { | |
259 | kernel_del_pbr_rule(rule); | |
260 | hash_release(zns->rules_hash, rule); | |
d5c52f76 | 261 | XFREE(MTYPE_TMP, rule); |
e69aa084 DS |
262 | } |
263 | } | |
264 | ||
265 | void zebra_pbr_client_close_cleanup(int sock) | |
266 | { | |
267 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
268 | ||
269 | hash_iterate(zns->rules_hash, zebra_pbr_cleanup_rules, &sock); | |
270 | } | |
271 | ||
7661461a PG |
272 | static void *pbr_ipset_alloc_intern(void *arg) |
273 | { | |
274 | struct zebra_pbr_ipset *zpi; | |
275 | struct zebra_pbr_ipset *new; | |
276 | ||
277 | zpi = (struct zebra_pbr_ipset *)arg; | |
278 | ||
279 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset)); | |
280 | ||
281 | memcpy(new, zpi, sizeof(*zpi)); | |
282 | ||
283 | return new; | |
284 | } | |
285 | ||
286 | void zebra_pbr_create_ipset(struct zebra_ns *zns, | |
287 | struct zebra_pbr_ipset *ipset) | |
288 | { | |
289 | (void)hash_get(zns->ipset_hash, ipset, pbr_ipset_alloc_intern); | |
290 | /* TODO: | |
291 | * - Netlink call | |
292 | */ | |
293 | } | |
294 | ||
295 | void zebra_pbr_destroy_ipset(struct zebra_ns *zns, | |
296 | struct zebra_pbr_ipset *ipset) | |
297 | { | |
298 | struct zebra_pbr_ipset *lookup; | |
299 | ||
300 | lookup = hash_lookup(zns->ipset_hash, ipset); | |
301 | /* TODO: | |
302 | * - Netlink destroy from kernel | |
303 | * - ?? destroy ipset entries before | |
304 | */ | |
305 | if (lookup) | |
306 | XFREE(MTYPE_TMP, lookup); | |
307 | else | |
308 | zlog_warn("%s: IPSet being deleted we know nothing about", | |
309 | __PRETTY_FUNCTION__); | |
310 | } | |
311 | ||
312 | static void *pbr_ipset_entry_alloc_intern(void *arg) | |
313 | { | |
314 | struct zebra_pbr_ipset_entry *zpi; | |
315 | struct zebra_pbr_ipset_entry *new; | |
316 | ||
317 | zpi = (struct zebra_pbr_ipset_entry *)arg; | |
318 | ||
319 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry)); | |
320 | ||
321 | memcpy(new, zpi, sizeof(*zpi)); | |
322 | ||
323 | return new; | |
324 | } | |
325 | ||
326 | void zebra_pbr_add_ipset_entry(struct zebra_ns *zns, | |
327 | struct zebra_pbr_ipset_entry *ipset) | |
328 | { | |
329 | (void)hash_get(zns->ipset_entry_hash, ipset, | |
330 | pbr_ipset_entry_alloc_intern); | |
331 | /* TODO: | |
332 | * - attach to ipset list | |
333 | * - Netlink add to kernel | |
334 | */ | |
335 | } | |
336 | ||
337 | void zebra_pbr_del_ipset_entry(struct zebra_ns *zns, | |
338 | struct zebra_pbr_ipset_entry *ipset) | |
339 | { | |
340 | struct zebra_pbr_ipset_entry *lookup; | |
341 | ||
342 | lookup = hash_lookup(zns->ipset_hash, ipset); | |
343 | /* TODO: | |
344 | * - Netlink destroy | |
345 | * - detach from ipset list | |
346 | * - ?? if no more entres, delete ipset | |
347 | */ | |
348 | if (lookup) | |
349 | XFREE(MTYPE_TMP, lookup); | |
350 | else | |
351 | zlog_warn("%s: IPSet being deleted we know nothing about", | |
352 | __PRETTY_FUNCTION__); | |
353 | } | |
354 | ||
942bf97b | 355 | /* |
356 | * Handle success or failure of rule (un)install in the kernel. | |
357 | */ | |
358 | void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, | |
942bf97b | 359 | enum southbound_results res) |
360 | { | |
b6c5d343 DS |
361 | switch (res) { |
362 | case SOUTHBOUND_INSTALL_SUCCESS: | |
363 | zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED); | |
364 | break; | |
365 | case SOUTHBOUND_INSTALL_FAILURE: | |
366 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL); | |
367 | break; | |
368 | case SOUTHBOUND_DELETE_SUCCESS: | |
369 | break; | |
370 | case SOUTHBOUND_DELETE_FAILURE: | |
371 | break; | |
372 | } | |
942bf97b | 373 | } |
374 | ||
375 | /* | |
376 | * Handle rule delete notification from kernel. | |
377 | */ | |
a0321978 | 378 | int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) |
942bf97b | 379 | { |
380 | return 0; | |
381 | } |