]>
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> | |
f80ec7e3 | 26 | #include <memory.h> |
73a829f7 | 27 | #include <hook.h> |
43fe6a2a | 28 | |
7f0ea8a4 | 29 | #include "zebra/zebra_router.h" |
942bf97b | 30 | #include "zebra/zebra_pbr.h" |
31 | #include "zebra/rt.h" | |
bf094f69 | 32 | #include "zebra/zapi_msg.h" |
f80ec7e3 | 33 | #include "zebra/zebra_memory.h" |
c0ea1ae7 | 34 | #include "zebra/zserv.h" |
f80ec7e3 PG |
35 | |
36 | /* definitions */ | |
37 | DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list") | |
942bf97b | 38 | |
39 | /* definitions */ | |
586f4ccf PG |
40 | static const struct message ipset_type_msg[] = { |
41 | {IPSET_NET_PORT_NET, "net,port,net"}, | |
42 | {IPSET_NET_PORT, "net,port"}, | |
43 | {IPSET_NET_NET, "net,net"}, | |
44 | {IPSET_NET, "net"}, | |
45 | {0} | |
46 | }; | |
942bf97b | 47 | |
be729dd7 PG |
48 | const struct message icmp_typecode_str[] = { |
49 | { 0 << 8, "echo-reply"}, | |
50 | { 0 << 8, "pong"}, | |
51 | { 3 << 8, "network-unreachable"}, | |
52 | { (3 << 8) + 1, "host-unreachable"}, | |
53 | { (3 << 8) + 2, "protocol-unreachable"}, | |
54 | { (3 << 8) + 3, "port-unreachable"}, | |
55 | { (3 << 8) + 4, "fragmentation-needed"}, | |
56 | { (3 << 8) + 5, "source-route-failed"}, | |
57 | { (3 << 8) + 6, "network-unknown"}, | |
58 | { (3 << 8) + 7, "host-unknown"}, | |
59 | { (3 << 8) + 9, "network-prohibited"}, | |
60 | { (3 << 8) + 10, "host-prohibited"}, | |
61 | { (3 << 8) + 11, "TOS-network-unreachable"}, | |
62 | { (3 << 8) + 12, "TOS-host-unreachable"}, | |
63 | { (3 << 8) + 13, "communication-prohibited"}, | |
64 | { (3 << 8) + 14, "host-precedence-violation"}, | |
65 | { (3 << 8) + 15, "precedence-cutoff"}, | |
66 | { 4 << 8, "source-quench"}, | |
67 | { 5 << 8, "network-redirect"}, | |
68 | { (5 << 8) + 1, "host-redirect"}, | |
69 | { (5 << 8) + 2, "TOS-network-redirect"}, | |
70 | { (5 << 8) + 3, "TOS-host-redirect"}, | |
71 | { 8 << 8, "echo-request"}, | |
72 | { 8 << 8, "ping"}, | |
73 | { 9 << 8, "router-advertisement"}, | |
74 | { 10 << 8, "router-solicitation"}, | |
75 | { 11 << 8, "ttl-zero-during-transit"}, | |
76 | { (11 << 8) + 1, "ttl-zero-during-reassembly"}, | |
77 | { 12 << 8, "ip-header-bad"}, | |
78 | { (12 << 8) + 1, "required-option-missing"}, | |
79 | { 13 << 8, "timestamp-request"}, | |
80 | { 14 << 8, "timestamp-reply"}, | |
81 | { 17 << 8, "address-mask-request"}, | |
82 | { 18 << 8, "address-mask-reply"}, | |
83 | {0} | |
84 | }; | |
85 | ||
dc993e76 PG |
86 | /* definitions */ |
87 | static const struct message tcp_value_str[] = { | |
88 | {TCP_HEADER_FIN, "FIN"}, | |
89 | {TCP_HEADER_SYN, "SYN"}, | |
90 | {TCP_HEADER_RST, "RST"}, | |
91 | {TCP_HEADER_PSH, "PSH"}, | |
92 | {TCP_HEADER_ACK, "ACK"}, | |
93 | {TCP_HEADER_URG, "URG"}, | |
94 | {0} | |
95 | }; | |
96 | ||
5ac5b7cc PG |
97 | static const struct message fragment_value_str[] = { |
98 | {1, "dont-fragment"}, | |
99 | {2, "is-fragment"}, | |
100 | {4, "first-fragment"}, | |
101 | {8, "last-fragment"}, | |
102 | {0} | |
103 | }; | |
104 | ||
942bf97b | 105 | /* static function declarations */ |
1c6fca1f | 106 | DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat, |
62f20a52 DS |
107 | (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts, |
108 | uint64_t *bytes), | |
109 | (ipset, pkts, bytes)) | |
110 | ||
1c6fca1f | 111 | DEFINE_HOOK(zebra_pbr_iptable_get_stat, |
62f20a52 DS |
112 | (struct zebra_pbr_iptable *iptable, uint64_t *pkts, |
113 | uint64_t *bytes), | |
114 | (iptable, pkts, bytes)) | |
115 | ||
1c6fca1f | 116 | DEFINE_HOOK(zebra_pbr_iptable_update, |
62f20a52 DS |
117 | (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable)); |
118 | ||
1c6fca1f | 119 | DEFINE_HOOK(zebra_pbr_ipset_entry_update, |
62f20a52 DS |
120 | (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset)); |
121 | ||
1c6fca1f | 122 | DEFINE_HOOK(zebra_pbr_ipset_update, |
62f20a52 | 123 | (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset)); |
942bf97b | 124 | |
125 | /* Private functions */ | |
126 | ||
127 | /* Public functions */ | |
43fe6a2a | 128 | void zebra_pbr_rules_free(void *arg) |
1fbfe5a5 | 129 | { |
43fe6a2a DS |
130 | struct zebra_pbr_rule *rule; |
131 | ||
132 | rule = (struct zebra_pbr_rule *)arg; | |
133 | ||
ebecd649 | 134 | (void)kernel_del_pbr_rule(rule); |
43fe6a2a DS |
135 | XFREE(MTYPE_TMP, rule); |
136 | } | |
137 | ||
138 | uint32_t zebra_pbr_rules_hash_key(void *arg) | |
139 | { | |
140 | struct zebra_pbr_rule *rule; | |
141 | uint32_t key; | |
142 | ||
143 | rule = (struct zebra_pbr_rule *)arg; | |
5dd0722d PG |
144 | key = jhash_3words(rule->rule.seq, rule->rule.priority, |
145 | rule->rule.action.table, | |
146 | prefix_hash_key(&rule->rule.filter.src_ip)); | |
a0321978 DS |
147 | if (rule->ifp) |
148 | key = jhash_1word(rule->ifp->ifindex, key); | |
149 | else | |
150 | key = jhash_1word(0, key); | |
151 | ||
5dd0722d PG |
152 | if (rule->rule.filter.fwmark) |
153 | key = jhash_1word(rule->rule.filter.fwmark, key); | |
1907e4b8 PG |
154 | else |
155 | key = jhash_1word(0, key); | |
7f0ea8a4 DS |
156 | |
157 | key = jhash_1word(rule->vrf_id, key); | |
158 | ||
5dd0722d PG |
159 | return jhash_3words(rule->rule.filter.src_port, |
160 | rule->rule.filter.dst_port, | |
161 | prefix_hash_key(&rule->rule.filter.dst_ip), | |
162 | jhash_1word(rule->rule.unique, key)); | |
43fe6a2a DS |
163 | } |
164 | ||
74df8d6d | 165 | bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) |
43fe6a2a DS |
166 | { |
167 | const struct zebra_pbr_rule *r1, *r2; | |
168 | ||
169 | r1 = (const struct zebra_pbr_rule *)arg1; | |
170 | r2 = (const struct zebra_pbr_rule *)arg2; | |
171 | ||
5dd0722d | 172 | if (r1->rule.seq != r2->rule.seq) |
74df8d6d | 173 | return false; |
43fe6a2a | 174 | |
5dd0722d | 175 | if (r1->rule.priority != r2->rule.priority) |
74df8d6d | 176 | return false; |
43fe6a2a | 177 | |
5dd0722d | 178 | if (r1->rule.unique != r2->rule.unique) |
74df8d6d | 179 | return false; |
b6c5d343 | 180 | |
5dd0722d | 181 | if (r1->rule.action.table != r2->rule.action.table) |
74df8d6d | 182 | return false; |
43fe6a2a | 183 | |
5dd0722d | 184 | if (r1->rule.filter.src_port != r2->rule.filter.src_port) |
74df8d6d | 185 | return false; |
43fe6a2a | 186 | |
5dd0722d | 187 | if (r1->rule.filter.dst_port != r2->rule.filter.dst_port) |
74df8d6d | 188 | return false; |
43fe6a2a | 189 | |
5dd0722d | 190 | if (r1->rule.filter.fwmark != r2->rule.filter.fwmark) |
74df8d6d | 191 | return false; |
1907e4b8 | 192 | |
5dd0722d | 193 | if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip)) |
74df8d6d | 194 | return false; |
43fe6a2a | 195 | |
5dd0722d | 196 | if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) |
74df8d6d | 197 | return false; |
43fe6a2a | 198 | |
a0321978 | 199 | if (r1->ifp != r2->ifp) |
74df8d6d | 200 | return false; |
a0321978 | 201 | |
7f0ea8a4 DS |
202 | if (r1->vrf_id != r2->vrf_id) |
203 | return false; | |
204 | ||
74df8d6d | 205 | return true; |
43fe6a2a DS |
206 | } |
207 | ||
f46bbab4 | 208 | struct pbr_rule_unique_lookup { |
8c3cd6c6 DS |
209 | struct zebra_pbr_rule *rule; |
210 | uint32_t unique; | |
37c606ff | 211 | struct interface *ifp; |
7f0ea8a4 | 212 | vrf_id_t vrf_id; |
8c3cd6c6 DS |
213 | }; |
214 | ||
215 | static int pbr_rule_lookup_unique_walker(struct hash_backet *b, void *data) | |
216 | { | |
f46bbab4 | 217 | struct pbr_rule_unique_lookup *pul = data; |
8c3cd6c6 DS |
218 | struct zebra_pbr_rule *rule = b->data; |
219 | ||
7f0ea8a4 DS |
220 | if (pul->unique == rule->rule.unique |
221 | && pul->ifp == rule->ifp | |
222 | && pul->vrf_id == rule->vrf_id) { | |
8c3cd6c6 DS |
223 | pul->rule = rule; |
224 | return HASHWALK_ABORT; | |
225 | } | |
226 | ||
227 | return HASHWALK_CONTINUE; | |
228 | } | |
229 | ||
62f20a52 DS |
230 | static struct zebra_pbr_rule * |
231 | pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) | |
8c3cd6c6 | 232 | { |
f46bbab4 | 233 | struct pbr_rule_unique_lookup pul; |
8c3cd6c6 | 234 | |
7f0ea8a4 DS |
235 | pul.unique = zrule->rule.unique; |
236 | pul.ifp = zrule->ifp; | |
8c3cd6c6 | 237 | pul.rule = NULL; |
7f0ea8a4 DS |
238 | pul.vrf_id = zrule->vrf_id; |
239 | hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); | |
8c3cd6c6 DS |
240 | |
241 | return pul.rule; | |
242 | } | |
243 | ||
7661461a PG |
244 | void zebra_pbr_ipset_free(void *arg) |
245 | { | |
246 | struct zebra_pbr_ipset *ipset; | |
247 | ||
248 | ipset = (struct zebra_pbr_ipset *)arg; | |
1c6fca1f | 249 | hook_call(zebra_pbr_ipset_update, 0, ipset); |
7661461a PG |
250 | XFREE(MTYPE_TMP, ipset); |
251 | } | |
252 | ||
253 | uint32_t zebra_pbr_ipset_hash_key(void *arg) | |
254 | { | |
255 | struct zebra_pbr_ipset *ipset = (struct zebra_pbr_ipset *)arg; | |
425bdd6b | 256 | uint32_t *pnt = (uint32_t *)&ipset->ipset_name; |
62f20a52 | 257 | uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de); |
7661461a | 258 | |
62f20a52 | 259 | return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key); |
7661461a PG |
260 | } |
261 | ||
74df8d6d | 262 | bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) |
7661461a PG |
263 | { |
264 | const struct zebra_pbr_ipset *r1, *r2; | |
265 | ||
266 | r1 = (const struct zebra_pbr_ipset *)arg1; | |
267 | r2 = (const struct zebra_pbr_ipset *)arg2; | |
268 | ||
269 | if (r1->type != r2->type) | |
74df8d6d | 270 | return false; |
7661461a | 271 | if (r1->unique != r2->unique) |
74df8d6d | 272 | return false; |
62f20a52 DS |
273 | if (r1->vrf_id != r2->vrf_id) |
274 | return false; | |
275 | ||
7661461a PG |
276 | if (strncmp(r1->ipset_name, r2->ipset_name, |
277 | ZEBRA_IPSET_NAME_SIZE)) | |
74df8d6d DS |
278 | return false; |
279 | return true; | |
7661461a PG |
280 | } |
281 | ||
282 | void zebra_pbr_ipset_entry_free(void *arg) | |
283 | { | |
284 | struct zebra_pbr_ipset_entry *ipset; | |
285 | ||
286 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
73a829f7 | 287 | |
1c6fca1f | 288 | hook_call(zebra_pbr_ipset_entry_update, 0, ipset); |
7661461a PG |
289 | |
290 | XFREE(MTYPE_TMP, ipset); | |
291 | } | |
292 | ||
293 | uint32_t zebra_pbr_ipset_entry_hash_key(void *arg) | |
294 | { | |
295 | struct zebra_pbr_ipset_entry *ipset; | |
296 | uint32_t key; | |
297 | ||
298 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
299 | key = prefix_hash_key(&ipset->src); | |
300 | key = jhash_1word(ipset->unique, key); | |
301 | key = jhash_1word(prefix_hash_key(&ipset->dst), key); | |
25d760c5 PG |
302 | key = jhash(&ipset->dst_port_min, 2, key); |
303 | key = jhash(&ipset->dst_port_max, 2, key); | |
304 | key = jhash(&ipset->src_port_min, 2, key); | |
305 | key = jhash(&ipset->src_port_max, 2, key); | |
306 | key = jhash(&ipset->proto, 1, key); | |
7661461a PG |
307 | |
308 | return key; | |
309 | } | |
310 | ||
74df8d6d | 311 | bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) |
7661461a PG |
312 | { |
313 | const struct zebra_pbr_ipset_entry *r1, *r2; | |
314 | ||
315 | r1 = (const struct zebra_pbr_ipset_entry *)arg1; | |
316 | r2 = (const struct zebra_pbr_ipset_entry *)arg2; | |
317 | ||
318 | if (r1->unique != r2->unique) | |
74df8d6d | 319 | return false; |
7661461a PG |
320 | |
321 | if (!prefix_same(&r1->src, &r2->src)) | |
74df8d6d | 322 | return false; |
7661461a PG |
323 | |
324 | if (!prefix_same(&r1->dst, &r2->dst)) | |
74df8d6d | 325 | return false; |
7661461a | 326 | |
25d760c5 | 327 | if (r1->src_port_min != r2->src_port_min) |
74df8d6d | 328 | return false; |
25d760c5 PG |
329 | |
330 | if (r1->src_port_max != r2->src_port_max) | |
74df8d6d | 331 | return false; |
25d760c5 PG |
332 | |
333 | if (r1->dst_port_min != r2->dst_port_min) | |
74df8d6d | 334 | return false; |
25d760c5 PG |
335 | |
336 | if (r1->dst_port_max != r2->dst_port_max) | |
74df8d6d | 337 | return false; |
25d760c5 PG |
338 | |
339 | if (r1->proto != r2->proto) | |
74df8d6d DS |
340 | return false; |
341 | return true; | |
7661461a PG |
342 | } |
343 | ||
7abd6c4f PG |
344 | void zebra_pbr_iptable_free(void *arg) |
345 | { | |
346 | struct zebra_pbr_iptable *iptable; | |
f80ec7e3 PG |
347 | struct listnode *node, *nnode; |
348 | char *name; | |
7abd6c4f PG |
349 | |
350 | iptable = (struct zebra_pbr_iptable *)arg; | |
1c6fca1f | 351 | hook_call(zebra_pbr_iptable_update, 0, iptable); |
7abd6c4f | 352 | |
f80ec7e3 PG |
353 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, |
354 | node, nnode, name)) { | |
355 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
356 | list_delete_node(iptable->interface_name_list, | |
357 | node); | |
358 | } | |
7abd6c4f PG |
359 | XFREE(MTYPE_TMP, iptable); |
360 | } | |
361 | ||
362 | uint32_t zebra_pbr_iptable_hash_key(void *arg) | |
363 | { | |
364 | struct zebra_pbr_iptable *iptable = (struct zebra_pbr_iptable *)arg; | |
365 | uint32_t *pnt = (uint32_t *)&(iptable->ipset_name); | |
366 | uint32_t key; | |
367 | ||
368 | key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, | |
369 | 0x63ab42de); | |
370 | key = jhash_1word(iptable->fwmark, key); | |
e7f7dad4 PG |
371 | key = jhash_1word(iptable->pkt_len_min, key); |
372 | key = jhash_1word(iptable->pkt_len_max, key); | |
dc993e76 PG |
373 | key = jhash_1word(iptable->tcp_flags, key); |
374 | key = jhash_1word(iptable->tcp_mask_flags, key); | |
4977bd6c | 375 | key = jhash_1word(iptable->dscp_value, key); |
5ac5b7cc | 376 | key = jhash_1word(iptable->fragment, key); |
62f20a52 DS |
377 | key = jhash_1word(iptable->vrf_id, key); |
378 | ||
7abd6c4f PG |
379 | return jhash_3words(iptable->filter_bm, iptable->type, |
380 | iptable->unique, key); | |
381 | } | |
382 | ||
74df8d6d | 383 | bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) |
7abd6c4f PG |
384 | { |
385 | const struct zebra_pbr_iptable *r1, *r2; | |
386 | ||
387 | r1 = (const struct zebra_pbr_iptable *)arg1; | |
388 | r2 = (const struct zebra_pbr_iptable *)arg2; | |
389 | ||
62f20a52 DS |
390 | if (r1->vrf_id != r2->vrf_id) |
391 | return 0; | |
7abd6c4f | 392 | if (r1->type != r2->type) |
74df8d6d | 393 | return false; |
7abd6c4f | 394 | if (r1->unique != r2->unique) |
74df8d6d | 395 | return false; |
7abd6c4f | 396 | if (r1->filter_bm != r2->filter_bm) |
74df8d6d | 397 | return false; |
7abd6c4f | 398 | if (r1->fwmark != r2->fwmark) |
74df8d6d | 399 | return false; |
7abd6c4f | 400 | if (r1->action != r2->action) |
74df8d6d | 401 | return false; |
7abd6c4f PG |
402 | if (strncmp(r1->ipset_name, r2->ipset_name, |
403 | ZEBRA_IPSET_NAME_SIZE)) | |
74df8d6d | 404 | return false; |
e7f7dad4 | 405 | if (r1->pkt_len_min != r2->pkt_len_min) |
74df8d6d | 406 | return false; |
e7f7dad4 | 407 | if (r1->pkt_len_max != r2->pkt_len_max) |
74df8d6d | 408 | return false; |
dc993e76 | 409 | if (r1->tcp_flags != r2->tcp_flags) |
74df8d6d | 410 | return false; |
dc993e76 | 411 | if (r1->tcp_mask_flags != r2->tcp_mask_flags) |
74df8d6d | 412 | return false; |
4977bd6c | 413 | if (r1->dscp_value != r2->dscp_value) |
74df8d6d | 414 | return false; |
5ac5b7cc | 415 | if (r1->fragment != r2->fragment) |
74df8d6d DS |
416 | return false; |
417 | return true; | |
7abd6c4f PG |
418 | } |
419 | ||
43fe6a2a DS |
420 | static void *pbr_rule_alloc_intern(void *arg) |
421 | { | |
422 | struct zebra_pbr_rule *zpr; | |
423 | struct zebra_pbr_rule *new; | |
424 | ||
425 | zpr = (struct zebra_pbr_rule *)arg; | |
426 | ||
427 | new = XCALLOC(MTYPE_TMP, sizeof(*new)); | |
428 | ||
429 | memcpy(new, zpr, sizeof(*zpr)); | |
430 | ||
431 | return new; | |
432 | } | |
433 | ||
7f0ea8a4 | 434 | void zebra_pbr_add_rule(struct zebra_pbr_rule *rule) |
43fe6a2a | 435 | { |
8c3cd6c6 | 436 | struct zebra_pbr_rule *unique = |
7f0ea8a4 | 437 | pbr_rule_lookup_unique(rule); |
8c3cd6c6 | 438 | |
7f0ea8a4 | 439 | (void)hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern); |
ebecd649 | 440 | (void)kernel_add_pbr_rule(rule); |
8c3cd6c6 DS |
441 | /* |
442 | * Rule Replace semantics, if we have an old, install the | |
443 | * new rule, look above, and then delete the old | |
444 | */ | |
445 | if (unique) | |
7f0ea8a4 | 446 | zebra_pbr_del_rule(unique); |
1fbfe5a5 DS |
447 | } |
448 | ||
7f0ea8a4 | 449 | void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) |
1fbfe5a5 | 450 | { |
43fe6a2a DS |
451 | struct zebra_pbr_rule *lookup; |
452 | ||
7f0ea8a4 | 453 | lookup = hash_lookup(zrouter.rules_hash, rule); |
ebecd649 | 454 | (void)kernel_del_pbr_rule(rule); |
43fe6a2a | 455 | |
d5c52f76 | 456 | if (lookup) { |
7f0ea8a4 | 457 | hash_release(zrouter.rules_hash, lookup); |
43fe6a2a | 458 | XFREE(MTYPE_TMP, lookup); |
d5c52f76 | 459 | } else |
9df414fe QY |
460 | zlog_debug("%s: Rule being deleted we know nothing about", |
461 | __PRETTY_FUNCTION__); | |
1fbfe5a5 DS |
462 | } |
463 | ||
e69aa084 DS |
464 | static void zebra_pbr_cleanup_rules(struct hash_backet *b, void *data) |
465 | { | |
e69aa084 DS |
466 | struct zebra_pbr_rule *rule = b->data; |
467 | int *sock = data; | |
468 | ||
469 | if (rule->sock == *sock) { | |
ebecd649 | 470 | (void)kernel_del_pbr_rule(rule); |
7f0ea8a4 | 471 | hash_release(zrouter.rules_hash, rule); |
d5c52f76 | 472 | XFREE(MTYPE_TMP, rule); |
e69aa084 DS |
473 | } |
474 | } | |
475 | ||
c2ef5232 PG |
476 | static void zebra_pbr_cleanup_ipset(struct hash_backet *b, void *data) |
477 | { | |
c2ef5232 PG |
478 | struct zebra_pbr_ipset *ipset = b->data; |
479 | int *sock = data; | |
480 | ||
73a829f7 | 481 | if (ipset->sock == *sock) { |
1c6fca1f | 482 | hook_call(zebra_pbr_ipset_update, 0, ipset); |
62f20a52 | 483 | hash_release(zrouter.ipset_hash, ipset); |
73a829f7 | 484 | } |
c2ef5232 PG |
485 | } |
486 | ||
487 | static void zebra_pbr_cleanup_ipset_entry(struct hash_backet *b, void *data) | |
488 | { | |
c2ef5232 PG |
489 | struct zebra_pbr_ipset_entry *ipset = b->data; |
490 | int *sock = data; | |
491 | ||
73a829f7 | 492 | if (ipset->sock == *sock) { |
1c6fca1f | 493 | hook_call(zebra_pbr_ipset_entry_update, 0, ipset); |
62f20a52 | 494 | hash_release(zrouter.ipset_entry_hash, ipset); |
73a829f7 | 495 | } |
c2ef5232 PG |
496 | } |
497 | ||
498 | static void zebra_pbr_cleanup_iptable(struct hash_backet *b, void *data) | |
499 | { | |
c2ef5232 PG |
500 | struct zebra_pbr_iptable *iptable = b->data; |
501 | int *sock = data; | |
502 | ||
73a829f7 | 503 | if (iptable->sock == *sock) { |
1c6fca1f | 504 | hook_call(zebra_pbr_iptable_update, 0, iptable); |
62f20a52 | 505 | hash_release(zrouter.iptable_hash, iptable); |
73a829f7 | 506 | } |
c2ef5232 PG |
507 | } |
508 | ||
4c0ec639 | 509 | static int zebra_pbr_client_close_cleanup(struct zserv *client) |
e69aa084 | 510 | { |
4c0ec639 | 511 | int sock = client->sock; |
e69aa084 | 512 | |
4c0ec639 PG |
513 | if (!sock) |
514 | return 0; | |
7f0ea8a4 | 515 | hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock); |
62f20a52 DS |
516 | hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock); |
517 | hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry, | |
518 | &sock); | |
519 | hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock); | |
4c0ec639 PG |
520 | return 1; |
521 | } | |
522 | ||
523 | void zebra_pbr_init(void) | |
524 | { | |
c0ea1ae7 | 525 | hook_register(zserv_client_close, zebra_pbr_client_close_cleanup); |
e69aa084 DS |
526 | } |
527 | ||
7661461a PG |
528 | static void *pbr_ipset_alloc_intern(void *arg) |
529 | { | |
530 | struct zebra_pbr_ipset *zpi; | |
531 | struct zebra_pbr_ipset *new; | |
532 | ||
533 | zpi = (struct zebra_pbr_ipset *)arg; | |
534 | ||
535 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset)); | |
536 | ||
537 | memcpy(new, zpi, sizeof(*zpi)); | |
538 | ||
539 | return new; | |
540 | } | |
541 | ||
62f20a52 | 542 | void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset) |
7661461a | 543 | { |
73a829f7 PG |
544 | int ret; |
545 | ||
62f20a52 | 546 | (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern); |
1c6fca1f | 547 | ret = hook_call(zebra_pbr_ipset_update, 1, ipset); |
73a829f7 | 548 | kernel_pbr_ipset_add_del_status(ipset, |
ea1c14f6 MS |
549 | ret ? ZEBRA_DPLANE_INSTALL_SUCCESS |
550 | : ZEBRA_DPLANE_INSTALL_FAILURE); | |
7661461a PG |
551 | } |
552 | ||
62f20a52 | 553 | void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) |
7661461a PG |
554 | { |
555 | struct zebra_pbr_ipset *lookup; | |
556 | ||
62f20a52 | 557 | lookup = hash_lookup(zrouter.ipset_hash, ipset); |
1c6fca1f | 558 | hook_call(zebra_pbr_ipset_update, 0, ipset); |
de67547d | 559 | if (lookup) { |
62f20a52 | 560 | hash_release(zrouter.ipset_hash, lookup); |
7661461a | 561 | XFREE(MTYPE_TMP, lookup); |
de67547d | 562 | } else |
9df414fe QY |
563 | zlog_debug( |
564 | "%s: IPSet Entry being deleted we know nothing about", | |
565 | __PRETTY_FUNCTION__); | |
7661461a PG |
566 | } |
567 | ||
ed78b7c8 PG |
568 | struct pbr_ipset_name_lookup { |
569 | struct zebra_pbr_ipset *ipset; | |
570 | char ipset_name[ZEBRA_IPSET_NAME_SIZE]; | |
571 | }; | |
572 | ||
5b0d92b8 | 573 | const char *zebra_pbr_ipset_type2str(uint32_t type) |
586f4ccf PG |
574 | { |
575 | return lookup_msg(ipset_type_msg, type, | |
576 | "Unrecognized IPset Type"); | |
577 | } | |
578 | ||
ed78b7c8 PG |
579 | static int zebra_pbr_ipset_pername_walkcb(struct hash_backet *backet, void *arg) |
580 | { | |
581 | struct pbr_ipset_name_lookup *pinl = | |
582 | (struct pbr_ipset_name_lookup *)arg; | |
583 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
584 | ||
585 | if (!strncmp(pinl->ipset_name, zpi->ipset_name, | |
586 | ZEBRA_IPSET_NAME_SIZE)) { | |
587 | pinl->ipset = zpi; | |
588 | return HASHWALK_ABORT; | |
589 | } | |
590 | return HASHWALK_CONTINUE; | |
591 | } | |
592 | ||
62f20a52 | 593 | struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname) |
d59c13af | 594 | { |
ed78b7c8 PG |
595 | struct pbr_ipset_name_lookup pinl; |
596 | struct pbr_ipset_name_lookup *ptr = &pinl; | |
597 | ||
d59c13af PG |
598 | if (!ipsetname) |
599 | return NULL; | |
ed78b7c8 PG |
600 | memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup)); |
601 | snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s", | |
602 | ipsetname); | |
62f20a52 | 603 | hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr); |
ed78b7c8 | 604 | return ptr->ipset; |
d59c13af PG |
605 | } |
606 | ||
7661461a PG |
607 | static void *pbr_ipset_entry_alloc_intern(void *arg) |
608 | { | |
609 | struct zebra_pbr_ipset_entry *zpi; | |
610 | struct zebra_pbr_ipset_entry *new; | |
611 | ||
612 | zpi = (struct zebra_pbr_ipset_entry *)arg; | |
613 | ||
614 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_ipset_entry)); | |
615 | ||
616 | memcpy(new, zpi, sizeof(*zpi)); | |
617 | ||
618 | return new; | |
619 | } | |
620 | ||
62f20a52 | 621 | void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset) |
7661461a | 622 | { |
73a829f7 PG |
623 | int ret; |
624 | ||
62f20a52 | 625 | (void)hash_get(zrouter.ipset_entry_hash, ipset, |
7661461a | 626 | pbr_ipset_entry_alloc_intern); |
1c6fca1f | 627 | ret = hook_call(zebra_pbr_ipset_entry_update, 1, ipset); |
73a829f7 | 628 | kernel_pbr_ipset_entry_add_del_status(ipset, |
ea1c14f6 MS |
629 | ret ? ZEBRA_DPLANE_INSTALL_SUCCESS |
630 | : ZEBRA_DPLANE_INSTALL_FAILURE); | |
7661461a PG |
631 | } |
632 | ||
62f20a52 | 633 | void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) |
7661461a PG |
634 | { |
635 | struct zebra_pbr_ipset_entry *lookup; | |
636 | ||
62f20a52 | 637 | lookup = hash_lookup(zrouter.ipset_entry_hash, ipset); |
1c6fca1f | 638 | hook_call(zebra_pbr_ipset_entry_update, 0, ipset); |
de67547d | 639 | if (lookup) { |
62f20a52 | 640 | hash_release(zrouter.ipset_entry_hash, lookup); |
7661461a | 641 | XFREE(MTYPE_TMP, lookup); |
de67547d | 642 | } else |
9df414fe QY |
643 | zlog_debug("%s: IPSet being deleted we know nothing about", |
644 | __PRETTY_FUNCTION__); | |
7661461a PG |
645 | } |
646 | ||
7abd6c4f PG |
647 | static void *pbr_iptable_alloc_intern(void *arg) |
648 | { | |
649 | struct zebra_pbr_iptable *zpi; | |
650 | struct zebra_pbr_iptable *new; | |
651 | ||
652 | zpi = (struct zebra_pbr_iptable *)arg; | |
653 | ||
654 | new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable)); | |
655 | ||
656 | memcpy(new, zpi, sizeof(*zpi)); | |
657 | ||
658 | return new; | |
659 | } | |
660 | ||
62f20a52 | 661 | void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable) |
7abd6c4f | 662 | { |
73a829f7 PG |
663 | int ret; |
664 | ||
62f20a52 | 665 | (void)hash_get(zrouter.iptable_hash, iptable, pbr_iptable_alloc_intern); |
1c6fca1f | 666 | ret = hook_call(zebra_pbr_iptable_update, 1, iptable); |
73a829f7 | 667 | kernel_pbr_iptable_add_del_status(iptable, |
ea1c14f6 MS |
668 | ret ? ZEBRA_DPLANE_INSTALL_SUCCESS |
669 | : ZEBRA_DPLANE_INSTALL_FAILURE); | |
7abd6c4f PG |
670 | } |
671 | ||
62f20a52 | 672 | void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) |
7abd6c4f | 673 | { |
f80ec7e3 | 674 | struct zebra_pbr_iptable *lookup; |
7abd6c4f | 675 | |
62f20a52 | 676 | lookup = hash_lookup(zrouter.iptable_hash, iptable); |
1c6fca1f | 677 | hook_call(zebra_pbr_iptable_update, 0, iptable); |
f80ec7e3 PG |
678 | if (lookup) { |
679 | struct listnode *node, *nnode; | |
680 | char *name; | |
681 | ||
62f20a52 | 682 | hash_release(zrouter.iptable_hash, lookup); |
f80ec7e3 PG |
683 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, |
684 | node, nnode, name)) { | |
685 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
686 | list_delete_node(iptable->interface_name_list, | |
687 | node); | |
688 | } | |
7abd6c4f | 689 | XFREE(MTYPE_TMP, lookup); |
f80ec7e3 | 690 | } else |
9df414fe QY |
691 | zlog_debug("%s: IPTable being deleted we know nothing about", |
692 | __PRETTY_FUNCTION__); | |
7abd6c4f PG |
693 | } |
694 | ||
942bf97b | 695 | /* |
696 | * Handle success or failure of rule (un)install in the kernel. | |
697 | */ | |
698 | void kernel_pbr_rule_add_del_status(struct zebra_pbr_rule *rule, | |
ea1c14f6 | 699 | enum zebra_dplane_status res) |
942bf97b | 700 | { |
b6c5d343 | 701 | switch (res) { |
ea1c14f6 | 702 | case ZEBRA_DPLANE_INSTALL_SUCCESS: |
b6c5d343 DS |
703 | zsend_rule_notify_owner(rule, ZAPI_RULE_INSTALLED); |
704 | break; | |
ea1c14f6 | 705 | case ZEBRA_DPLANE_INSTALL_FAILURE: |
b6c5d343 DS |
706 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_INSTALL); |
707 | break; | |
ea1c14f6 | 708 | case ZEBRA_DPLANE_DELETE_SUCCESS: |
0f03639d | 709 | zsend_rule_notify_owner(rule, ZAPI_RULE_REMOVED); |
b6c5d343 | 710 | break; |
ea1c14f6 | 711 | case ZEBRA_DPLANE_DELETE_FAILURE: |
34d9d5be | 712 | zsend_rule_notify_owner(rule, ZAPI_RULE_FAIL_REMOVE); |
b6c5d343 | 713 | break; |
ea1c14f6 MS |
714 | case ZEBRA_DPLANE_STATUS_NONE: |
715 | break; | |
b6c5d343 | 716 | } |
942bf97b | 717 | } |
718 | ||
425bdd6b PG |
719 | /* |
720 | * Handle success or failure of ipset (un)install in the kernel. | |
721 | */ | |
722 | void kernel_pbr_ipset_add_del_status(struct zebra_pbr_ipset *ipset, | |
ea1c14f6 | 723 | enum zebra_dplane_status res) |
425bdd6b PG |
724 | { |
725 | switch (res) { | |
ea1c14f6 | 726 | case ZEBRA_DPLANE_INSTALL_SUCCESS: |
425bdd6b PG |
727 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_INSTALLED); |
728 | break; | |
ea1c14f6 | 729 | case ZEBRA_DPLANE_INSTALL_FAILURE: |
425bdd6b PG |
730 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_INSTALL); |
731 | break; | |
ea1c14f6 | 732 | case ZEBRA_DPLANE_DELETE_SUCCESS: |
4c550bcf PG |
733 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_REMOVED); |
734 | break; | |
ea1c14f6 | 735 | case ZEBRA_DPLANE_DELETE_FAILURE: |
34d9d5be | 736 | zsend_ipset_notify_owner(ipset, ZAPI_IPSET_FAIL_REMOVE); |
425bdd6b | 737 | break; |
ea1c14f6 MS |
738 | case ZEBRA_DPLANE_STATUS_NONE: |
739 | break; | |
425bdd6b PG |
740 | } |
741 | } | |
742 | ||
743 | /* | |
744 | * Handle success or failure of ipset (un)install in the kernel. | |
745 | */ | |
746 | void kernel_pbr_ipset_entry_add_del_status( | |
747 | struct zebra_pbr_ipset_entry *ipset, | |
ea1c14f6 | 748 | enum zebra_dplane_status res) |
425bdd6b PG |
749 | { |
750 | switch (res) { | |
ea1c14f6 | 751 | case ZEBRA_DPLANE_INSTALL_SUCCESS: |
425bdd6b PG |
752 | zsend_ipset_entry_notify_owner(ipset, |
753 | ZAPI_IPSET_ENTRY_INSTALLED); | |
754 | break; | |
ea1c14f6 | 755 | case ZEBRA_DPLANE_INSTALL_FAILURE: |
425bdd6b PG |
756 | zsend_ipset_entry_notify_owner(ipset, |
757 | ZAPI_IPSET_ENTRY_FAIL_INSTALL); | |
758 | break; | |
ea1c14f6 | 759 | case ZEBRA_DPLANE_DELETE_SUCCESS: |
4c550bcf PG |
760 | zsend_ipset_entry_notify_owner(ipset, |
761 | ZAPI_IPSET_ENTRY_REMOVED); | |
762 | break; | |
ea1c14f6 | 763 | case ZEBRA_DPLANE_DELETE_FAILURE: |
4c550bcf | 764 | zsend_ipset_entry_notify_owner(ipset, |
34d9d5be | 765 | ZAPI_IPSET_ENTRY_FAIL_REMOVE); |
425bdd6b | 766 | break; |
ea1c14f6 MS |
767 | case ZEBRA_DPLANE_STATUS_NONE: |
768 | break; | |
425bdd6b PG |
769 | } |
770 | } | |
771 | ||
7abd6c4f PG |
772 | /* |
773 | * Handle success or failure of ipset (un)install in the kernel. | |
774 | */ | |
775 | void kernel_pbr_iptable_add_del_status(struct zebra_pbr_iptable *iptable, | |
ea1c14f6 | 776 | enum zebra_dplane_status res) |
7abd6c4f PG |
777 | { |
778 | switch (res) { | |
ea1c14f6 | 779 | case ZEBRA_DPLANE_INSTALL_SUCCESS: |
7abd6c4f PG |
780 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_INSTALLED); |
781 | break; | |
ea1c14f6 | 782 | case ZEBRA_DPLANE_INSTALL_FAILURE: |
7abd6c4f PG |
783 | zsend_iptable_notify_owner(iptable, ZAPI_IPTABLE_FAIL_INSTALL); |
784 | break; | |
ea1c14f6 | 785 | case ZEBRA_DPLANE_DELETE_SUCCESS: |
4c550bcf PG |
786 | zsend_iptable_notify_owner(iptable, |
787 | ZAPI_IPTABLE_REMOVED); | |
788 | break; | |
ea1c14f6 | 789 | case ZEBRA_DPLANE_DELETE_FAILURE: |
4c550bcf | 790 | zsend_iptable_notify_owner(iptable, |
34d9d5be | 791 | ZAPI_IPTABLE_FAIL_REMOVE); |
7abd6c4f | 792 | break; |
ea1c14f6 MS |
793 | case ZEBRA_DPLANE_STATUS_NONE: |
794 | break; | |
7abd6c4f PG |
795 | } |
796 | } | |
797 | ||
942bf97b | 798 | /* |
799 | * Handle rule delete notification from kernel. | |
800 | */ | |
a0321978 | 801 | int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) |
942bf97b | 802 | { |
803 | return 0; | |
804 | } | |
586f4ccf PG |
805 | |
806 | struct zebra_pbr_ipset_entry_unique_display { | |
807 | struct zebra_pbr_ipset *zpi; | |
808 | struct vty *vty; | |
73a829f7 | 809 | struct zebra_ns *zns; |
586f4ccf PG |
810 | }; |
811 | ||
812 | struct zebra_pbr_env_display { | |
813 | struct zebra_ns *zns; | |
814 | struct vty *vty; | |
7929821a | 815 | char *name; |
586f4ccf PG |
816 | }; |
817 | ||
818 | static const char *zebra_pbr_prefix2str(union prefixconstptr pu, | |
819 | char *str, int size) | |
820 | { | |
821 | const struct prefix *p = pu.p; | |
822 | char buf[PREFIX2STR_BUFFER]; | |
823 | ||
824 | if (p->family == AF_INET && p->prefixlen == IPV4_MAX_PREFIXLEN) { | |
825 | snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, | |
826 | buf, PREFIX2STR_BUFFER)); | |
827 | return str; | |
828 | } | |
829 | return prefix2str(pu, str, size); | |
830 | } | |
831 | ||
be729dd7 PG |
832 | static void zebra_pbr_display_icmp(struct vty *vty, |
833 | struct zebra_pbr_ipset_entry *zpie) | |
834 | { | |
835 | char decoded_str[20]; | |
836 | uint16_t port; | |
837 | ||
838 | /* range icmp type */ | |
839 | if (zpie->src_port_max || zpie->dst_port_max) { | |
840 | vty_out(vty, ":icmp:[type <%d:%d>;code <%d:%d>", | |
841 | zpie->src_port_min, zpie->src_port_max, | |
842 | zpie->dst_port_min, zpie->dst_port_max); | |
843 | } else { | |
844 | port = ((zpie->src_port_min << 8) & 0xff00) + | |
845 | (zpie->dst_port_min & 0xff); | |
846 | memset(decoded_str, 0, sizeof(decoded_str)); | |
847 | sprintf(decoded_str, "%d/%d", | |
848 | zpie->src_port_min, | |
849 | zpie->dst_port_min); | |
850 | vty_out(vty, ":icmp:%s", | |
851 | lookup_msg(icmp_typecode_str, | |
852 | port, decoded_str)); | |
853 | } | |
854 | } | |
855 | ||
25d760c5 PG |
856 | static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, |
857 | uint16_t port_min, uint16_t port_max, | |
858 | uint8_t proto) | |
859 | { | |
860 | if (!(filter_bm & PBR_FILTER_PROTO)) { | |
861 | if (port_max) | |
862 | vty_out(vty, ":udp/tcp:%d-%d", | |
863 | port_min, port_max); | |
864 | else | |
865 | vty_out(vty, ":udp/tcp:%d", | |
866 | port_min); | |
867 | } else { | |
868 | if (port_max) | |
869 | vty_out(vty, ":proto %d:%d-%d", | |
870 | proto, port_min, port_max); | |
871 | else | |
872 | vty_out(vty, ":proto %d:%d", | |
873 | proto, port_min); | |
874 | } | |
875 | } | |
876 | ||
586f4ccf PG |
877 | static int zebra_pbr_show_ipset_entry_walkcb(struct hash_backet *backet, |
878 | void *arg) | |
879 | { | |
880 | struct zebra_pbr_ipset_entry_unique_display *unique = | |
881 | (struct zebra_pbr_ipset_entry_unique_display *)arg; | |
882 | struct zebra_pbr_ipset *zpi = unique->zpi; | |
883 | struct vty *vty = unique->vty; | |
884 | struct zebra_pbr_ipset_entry *zpie = | |
885 | (struct zebra_pbr_ipset_entry *)backet->data; | |
73a829f7 | 886 | uint64_t pkts = 0, bytes = 0; |
73a829f7 | 887 | int ret = 0; |
586f4ccf PG |
888 | |
889 | if (zpie->backpointer != zpi) | |
890 | return HASHWALK_CONTINUE; | |
891 | ||
25d760c5 PG |
892 | if ((zpi->type == IPSET_NET_NET) || |
893 | (zpi->type == IPSET_NET_PORT_NET)) { | |
586f4ccf PG |
894 | char buf[PREFIX_STRLEN]; |
895 | ||
896 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
897 | vty_out(vty, "\tfrom %s", buf); | |
be729dd7 PG |
898 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
899 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
900 | zebra_pbr_display_port(vty, zpie->filter_bm, |
901 | zpie->src_port_min, | |
902 | zpie->src_port_max, | |
903 | zpie->proto); | |
586f4ccf PG |
904 | vty_out(vty, " to "); |
905 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
906 | vty_out(vty, "%s", buf); | |
be729dd7 PG |
907 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
908 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
909 | zebra_pbr_display_port(vty, zpie->filter_bm, |
910 | zpie->dst_port_min, | |
911 | zpie->dst_port_max, | |
912 | zpie->proto); | |
be729dd7 PG |
913 | if (zpie->proto == IPPROTO_ICMP) |
914 | zebra_pbr_display_icmp(vty, zpie); | |
25d760c5 PG |
915 | } else if ((zpi->type == IPSET_NET) || |
916 | (zpi->type == IPSET_NET_PORT)) { | |
586f4ccf PG |
917 | char buf[PREFIX_STRLEN]; |
918 | ||
919 | if (zpie->filter_bm & PBR_FILTER_SRC_IP) { | |
920 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
921 | vty_out(vty, "\tfrom %s", buf); | |
922 | } | |
be729dd7 PG |
923 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
924 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
925 | zebra_pbr_display_port(vty, zpie->filter_bm, |
926 | zpie->src_port_min, | |
927 | zpie->src_port_max, | |
928 | zpie->proto); | |
586f4ccf PG |
929 | if (zpie->filter_bm & PBR_FILTER_DST_IP) { |
930 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
931 | vty_out(vty, "\tto %s", buf); | |
932 | } | |
be729dd7 PG |
933 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
934 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
935 | zebra_pbr_display_port(vty, zpie->filter_bm, |
936 | zpie->dst_port_min, | |
937 | zpie->dst_port_max, | |
938 | zpie->proto); | |
be729dd7 PG |
939 | if (zpie->proto == IPPROTO_ICMP) |
940 | zebra_pbr_display_icmp(vty, zpie); | |
586f4ccf PG |
941 | } |
942 | vty_out(vty, " (%u)\n", zpie->unique); | |
943 | ||
1c6fca1f | 944 | ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts, |
62f20a52 | 945 | &bytes); |
73a829f7 PG |
946 | if (ret && pkts > 0) |
947 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
948 | pkts, bytes); | |
586f4ccf PG |
949 | return HASHWALK_CONTINUE; |
950 | } | |
951 | ||
952 | static int zebra_pbr_show_ipset_walkcb(struct hash_backet *backet, void *arg) | |
953 | { | |
954 | struct zebra_pbr_env_display *uniqueipset = | |
955 | (struct zebra_pbr_env_display *)arg; | |
956 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)backet->data; | |
957 | struct zebra_pbr_ipset_entry_unique_display unique; | |
958 | struct vty *vty = uniqueipset->vty; | |
959 | struct zebra_ns *zns = uniqueipset->zns; | |
960 | ||
961 | vty_out(vty, "IPset %s type %s\n", zpi->ipset_name, | |
962 | zebra_pbr_ipset_type2str(zpi->type)); | |
963 | unique.vty = vty; | |
964 | unique.zpi = zpi; | |
73a829f7 | 965 | unique.zns = zns; |
62f20a52 | 966 | hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb, |
586f4ccf PG |
967 | &unique); |
968 | vty_out(vty, "\n"); | |
969 | return HASHWALK_CONTINUE; | |
970 | } | |
971 | ||
dc993e76 PG |
972 | size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len, |
973 | uint16_t tcp_val) | |
974 | { | |
975 | size_t len_written = 0; | |
976 | static struct message nt = {0}; | |
977 | const struct message *pnt; | |
978 | int incr = 0; | |
979 | ||
980 | for (pnt = tcp_value_str; | |
981 | memcmp(pnt, &nt, sizeof(struct message)); pnt++) | |
982 | if (pnt->key & tcp_val) { | |
983 | len_written += snprintf(buffer + len_written, | |
984 | len - len_written, | |
985 | "%s%s", incr ? | |
986 | ",":"", pnt->str); | |
987 | incr++; | |
988 | } | |
989 | return len_written; | |
990 | } | |
991 | ||
586f4ccf PG |
992 | /* |
993 | */ | |
994 | void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) | |
995 | { | |
996 | struct zebra_pbr_ipset *zpi; | |
997 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
998 | struct zebra_pbr_ipset_entry_unique_display unique; | |
999 | struct zebra_pbr_env_display uniqueipset; | |
1000 | ||
1001 | if (ipsetname) { | |
62f20a52 | 1002 | zpi = zebra_pbr_lookup_ipset_pername(ipsetname); |
586f4ccf PG |
1003 | if (!zpi) { |
1004 | vty_out(vty, "No IPset %s found\n", ipsetname); | |
1005 | return; | |
1006 | } | |
1007 | vty_out(vty, "IPset %s type %s\n", ipsetname, | |
1008 | zebra_pbr_ipset_type2str(zpi->type)); | |
1009 | ||
1010 | unique.vty = vty; | |
1011 | unique.zpi = zpi; | |
73a829f7 | 1012 | unique.zns = zns; |
62f20a52 DS |
1013 | hash_walk(zrouter.ipset_entry_hash, |
1014 | zebra_pbr_show_ipset_entry_walkcb, &unique); | |
586f4ccf PG |
1015 | return; |
1016 | } | |
1017 | uniqueipset.zns = zns; | |
1018 | uniqueipset.vty = vty; | |
7929821a | 1019 | uniqueipset.name = NULL; |
62f20a52 | 1020 | hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb, |
586f4ccf PG |
1021 | &uniqueipset); |
1022 | } | |
1023 | ||
1024 | struct pbr_rule_fwmark_lookup { | |
1025 | struct zebra_pbr_rule *ptr; | |
1026 | uint32_t fwmark; | |
1027 | }; | |
1028 | ||
1029 | static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_backet *backet, | |
1030 | void *arg) | |
1031 | { | |
1032 | struct pbr_rule_fwmark_lookup *iprule = | |
1033 | (struct pbr_rule_fwmark_lookup *)arg; | |
1034 | struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)backet->data; | |
1035 | ||
1036 | if (iprule->fwmark == zpr->rule.filter.fwmark) { | |
1037 | iprule->ptr = zpr; | |
1038 | return HASHWALK_ABORT; | |
1039 | } | |
1040 | return HASHWALK_CONTINUE; | |
1041 | } | |
1042 | ||
7929821a PG |
1043 | static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, |
1044 | struct vty *vty, | |
1045 | struct zebra_ns *zns) | |
586f4ccf | 1046 | { |
73a829f7 PG |
1047 | int ret; |
1048 | uint64_t pkts = 0, bytes = 0; | |
586f4ccf PG |
1049 | |
1050 | vty_out(vty, "IPtable %s action %s (%u)\n", iptable->ipset_name, | |
1051 | iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", | |
1052 | iptable->unique); | |
0b328d3f PG |
1053 | if (iptable->type == IPSET_NET_PORT || |
1054 | iptable->type == IPSET_NET_PORT_NET) { | |
1055 | if (!(iptable->filter_bm & MATCH_ICMP_SET)) { | |
1056 | if (iptable->filter_bm & PBR_FILTER_DST_PORT) | |
1057 | vty_out(vty, "\t lookup dst port\n"); | |
1058 | else if (iptable->filter_bm & PBR_FILTER_SRC_PORT) | |
1059 | vty_out(vty, "\t lookup src port\n"); | |
1060 | } | |
1061 | } | |
e7f7dad4 PG |
1062 | if (iptable->pkt_len_min || iptable->pkt_len_max) { |
1063 | if (!iptable->pkt_len_max) | |
1064 | vty_out(vty, "\t pkt len %u\n", | |
1065 | iptable->pkt_len_min); | |
1066 | else | |
1067 | vty_out(vty, "\t pkt len [%u;%u]\n", | |
1068 | iptable->pkt_len_min, | |
1069 | iptable->pkt_len_max); | |
1070 | } | |
dc993e76 PG |
1071 | if (iptable->tcp_flags || iptable->tcp_mask_flags) { |
1072 | char tcp_flag_str[64]; | |
1073 | char tcp_flag_mask_str[64]; | |
1074 | ||
1075 | zebra_pbr_tcpflags_snprintf(tcp_flag_str, | |
1076 | sizeof(tcp_flag_str), | |
1077 | iptable->tcp_flags); | |
1078 | zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str, | |
1079 | sizeof(tcp_flag_mask_str), | |
1080 | iptable->tcp_mask_flags); | |
1081 | vty_out(vty, "\t tcpflags [%s/%s]\n", | |
1082 | tcp_flag_str, tcp_flag_mask_str); | |
1083 | } | |
69214c57 PG |
1084 | if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) { |
1085 | vty_out(vty, "\t dscp %s %d\n", | |
1086 | iptable->filter_bm & MATCH_DSCP_INVERSE_SET ? | |
1087 | "not" : "", iptable->dscp_value); | |
1088 | } | |
5ac5b7cc PG |
1089 | if (iptable->fragment) { |
1090 | char val_str[10]; | |
1091 | ||
1092 | sprintf(val_str, "%d", iptable->fragment); | |
1093 | vty_out(vty, "\t fragment%s %s\n", | |
1094 | iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ? | |
1095 | " not" : "", lookup_msg(fragment_value_str, | |
1096 | iptable->fragment, val_str)); | |
1097 | } | |
1c6fca1f | 1098 | ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts, |
62f20a52 | 1099 | &bytes); |
73a829f7 PG |
1100 | if (ret && pkts > 0) |
1101 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
1102 | pkts, bytes); | |
586f4ccf PG |
1103 | if (iptable->action != ZEBRA_IPTABLES_DROP) { |
1104 | struct pbr_rule_fwmark_lookup prfl; | |
1105 | ||
1106 | prfl.fwmark = iptable->fwmark; | |
1107 | prfl.ptr = NULL; | |
7f0ea8a4 | 1108 | hash_walk(zrouter.rules_hash, |
586f4ccf PG |
1109 | &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl); |
1110 | if (prfl.ptr) { | |
1111 | struct zebra_pbr_rule *zpr = prfl.ptr; | |
1112 | ||
1113 | vty_out(vty, "\t table %u, fwmark %u\n", | |
1114 | zpr->rule.action.table, | |
1115 | prfl.fwmark); | |
1116 | } | |
1117 | } | |
7929821a PG |
1118 | } |
1119 | ||
1120 | static int zebra_pbr_show_iptable_walkcb(struct hash_backet *backet, void *arg) | |
1121 | { | |
1122 | struct zebra_pbr_iptable *iptable = | |
1123 | (struct zebra_pbr_iptable *)backet->data; | |
1124 | struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; | |
1125 | struct vty *vty = env->vty; | |
1126 | struct zebra_ns *zns = env->zns; | |
1127 | char *iptable_name = env->name; | |
1128 | ||
1129 | if (!iptable_name) | |
1130 | zebra_pbr_show_iptable_unit(iptable, vty, zns); | |
1131 | else if (!strncmp(iptable_name, | |
1132 | iptable->ipset_name, | |
1133 | ZEBRA_IPSET_NAME_SIZE)) | |
1134 | zebra_pbr_show_iptable_unit(iptable, vty, zns); | |
586f4ccf PG |
1135 | return HASHWALK_CONTINUE; |
1136 | } | |
1137 | ||
7929821a | 1138 | void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name) |
586f4ccf PG |
1139 | { |
1140 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
1141 | struct zebra_pbr_env_display env; | |
1142 | ||
1143 | env.vty = vty; | |
1144 | env.zns = zns; | |
7929821a | 1145 | env.name = iptable_name; |
62f20a52 | 1146 | hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env); |
586f4ccf | 1147 | } |
f80ec7e3 PG |
1148 | |
1149 | void zebra_pbr_iptable_update_interfacelist(struct stream *s, | |
1150 | struct zebra_pbr_iptable *zpi) | |
1151 | { | |
1152 | uint32_t i = 0, index; | |
1153 | struct interface *ifp; | |
1154 | char *name; | |
1155 | ||
1156 | for (i = 0; i < zpi->nb_interface; i++) { | |
1157 | STREAM_GETL(s, index); | |
1158 | ifp = if_lookup_by_index(index, zpi->vrf_id); | |
1159 | if (!ifp) | |
1160 | continue; | |
1161 | name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name); | |
1162 | listnode_add(zpi->interface_name_list, name); | |
1163 | } | |
1164 | stream_failure: | |
1165 | return; | |
1166 | } |