]>
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" |
c0ea1ae7 | 33 | #include "zebra/zserv.h" |
8eeca5a2 | 34 | #include "zebra/debug.h" |
59f47eb0 | 35 | #include "zebra/zebra_neigh.h" |
f80ec7e3 PG |
36 | |
37 | /* definitions */ | |
bf8d3d6a | 38 | DEFINE_MTYPE_STATIC(ZEBRA, PBR_IPTABLE_IFNAME, "PBR interface list"); |
c0ce4875 | 39 | DEFINE_MTYPE(ZEBRA, PBR_OBJ, "PBR"); |
942bf97b | 40 | |
41 | /* definitions */ | |
586f4ccf PG |
42 | static const struct message ipset_type_msg[] = { |
43 | {IPSET_NET_PORT_NET, "net,port,net"}, | |
44 | {IPSET_NET_PORT, "net,port"}, | |
45 | {IPSET_NET_NET, "net,net"}, | |
46 | {IPSET_NET, "net"}, | |
47 | {0} | |
48 | }; | |
942bf97b | 49 | |
be729dd7 PG |
50 | const struct message icmp_typecode_str[] = { |
51 | { 0 << 8, "echo-reply"}, | |
52 | { 0 << 8, "pong"}, | |
53 | { 3 << 8, "network-unreachable"}, | |
54 | { (3 << 8) + 1, "host-unreachable"}, | |
55 | { (3 << 8) + 2, "protocol-unreachable"}, | |
56 | { (3 << 8) + 3, "port-unreachable"}, | |
57 | { (3 << 8) + 4, "fragmentation-needed"}, | |
58 | { (3 << 8) + 5, "source-route-failed"}, | |
59 | { (3 << 8) + 6, "network-unknown"}, | |
60 | { (3 << 8) + 7, "host-unknown"}, | |
61 | { (3 << 8) + 9, "network-prohibited"}, | |
62 | { (3 << 8) + 10, "host-prohibited"}, | |
63 | { (3 << 8) + 11, "TOS-network-unreachable"}, | |
64 | { (3 << 8) + 12, "TOS-host-unreachable"}, | |
65 | { (3 << 8) + 13, "communication-prohibited"}, | |
66 | { (3 << 8) + 14, "host-precedence-violation"}, | |
67 | { (3 << 8) + 15, "precedence-cutoff"}, | |
68 | { 4 << 8, "source-quench"}, | |
69 | { 5 << 8, "network-redirect"}, | |
70 | { (5 << 8) + 1, "host-redirect"}, | |
71 | { (5 << 8) + 2, "TOS-network-redirect"}, | |
72 | { (5 << 8) + 3, "TOS-host-redirect"}, | |
73 | { 8 << 8, "echo-request"}, | |
74 | { 8 << 8, "ping"}, | |
75 | { 9 << 8, "router-advertisement"}, | |
76 | { 10 << 8, "router-solicitation"}, | |
77 | { 11 << 8, "ttl-zero-during-transit"}, | |
78 | { (11 << 8) + 1, "ttl-zero-during-reassembly"}, | |
79 | { 12 << 8, "ip-header-bad"}, | |
80 | { (12 << 8) + 1, "required-option-missing"}, | |
81 | { 13 << 8, "timestamp-request"}, | |
82 | { 14 << 8, "timestamp-reply"}, | |
83 | { 17 << 8, "address-mask-request"}, | |
84 | { 18 << 8, "address-mask-reply"}, | |
85 | {0} | |
86 | }; | |
87 | ||
c9b1139a PG |
88 | const struct message icmpv6_typecode_str[] = { |
89 | { 128 << 8, "echo-request"}, | |
90 | { 129 << 8, "echo-reply"}, | |
91 | { 1 << 8, "no-route"}, | |
92 | { (1 << 8) + 1, "communication-prohibited"}, | |
93 | { (1 << 8) + 3, "address-unreachable"}, | |
94 | { (1 << 8) + 4, "port-unreachable"}, | |
95 | { (2 << 8), "packet-too-big"}, | |
96 | { 3 << 0, "ttl-zero-during-transit"}, | |
97 | { (3 << 8) + 1, "ttl-zero-during-reassembly"}, | |
98 | { 4 << 0, "bad-header"}, | |
99 | { (4 << 0) + 1, "unknown-header-type"}, | |
100 | { (4 << 0) + 2, "unknown-option"}, | |
101 | { 133 << 8, "router-solicitation"}, | |
102 | { 134 << 8, "router-advertisement"}, | |
103 | { 135 << 8, "neighbor-solicitation"}, | |
104 | { 136 << 8, "neighbor-advertisement"}, | |
105 | { 137 << 8, "redirect"}, | |
106 | {0} | |
107 | }; | |
108 | ||
dc993e76 PG |
109 | /* definitions */ |
110 | static const struct message tcp_value_str[] = { | |
111 | {TCP_HEADER_FIN, "FIN"}, | |
112 | {TCP_HEADER_SYN, "SYN"}, | |
113 | {TCP_HEADER_RST, "RST"}, | |
114 | {TCP_HEADER_PSH, "PSH"}, | |
115 | {TCP_HEADER_ACK, "ACK"}, | |
116 | {TCP_HEADER_URG, "URG"}, | |
117 | {0} | |
118 | }; | |
119 | ||
5ac5b7cc PG |
120 | static const struct message fragment_value_str[] = { |
121 | {1, "dont-fragment"}, | |
122 | {2, "is-fragment"}, | |
123 | {4, "first-fragment"}, | |
124 | {8, "last-fragment"}, | |
125 | {0} | |
126 | }; | |
127 | ||
59f47eb0 AK |
128 | struct zebra_pbr_env_display { |
129 | struct zebra_ns *zns; | |
130 | struct vty *vty; | |
131 | char *name; | |
132 | }; | |
133 | ||
942bf97b | 134 | /* static function declarations */ |
1c6fca1f | 135 | DEFINE_HOOK(zebra_pbr_ipset_entry_get_stat, |
62f20a52 DS |
136 | (struct zebra_pbr_ipset_entry *ipset, uint64_t *pkts, |
137 | uint64_t *bytes), | |
8451921b | 138 | (ipset, pkts, bytes)); |
62f20a52 | 139 | |
1c6fca1f | 140 | DEFINE_HOOK(zebra_pbr_iptable_get_stat, |
62f20a52 DS |
141 | (struct zebra_pbr_iptable *iptable, uint64_t *pkts, |
142 | uint64_t *bytes), | |
8451921b | 143 | (iptable, pkts, bytes)); |
62f20a52 | 144 | |
1c6fca1f | 145 | DEFINE_HOOK(zebra_pbr_iptable_update, |
62f20a52 DS |
146 | (int cmd, struct zebra_pbr_iptable *iptable), (cmd, iptable)); |
147 | ||
1c6fca1f | 148 | DEFINE_HOOK(zebra_pbr_ipset_entry_update, |
62f20a52 DS |
149 | (int cmd, struct zebra_pbr_ipset_entry *ipset), (cmd, ipset)); |
150 | ||
1c6fca1f | 151 | DEFINE_HOOK(zebra_pbr_ipset_update, |
62f20a52 | 152 | (int cmd, struct zebra_pbr_ipset *ipset), (cmd, ipset)); |
942bf97b | 153 | |
59f47eb0 AK |
154 | /* resolve nexthop for dataplane (dpdk) programming */ |
155 | static bool zebra_pbr_expand_action; | |
156 | ||
942bf97b | 157 | /* Private functions */ |
158 | ||
159 | /* Public functions */ | |
43fe6a2a | 160 | void zebra_pbr_rules_free(void *arg) |
1fbfe5a5 | 161 | { |
43fe6a2a DS |
162 | struct zebra_pbr_rule *rule; |
163 | ||
164 | rule = (struct zebra_pbr_rule *)arg; | |
165 | ||
f62e5480 | 166 | (void)dplane_pbr_rule_delete(rule); |
c0ce4875 | 167 | XFREE(MTYPE_PBR_OBJ, rule); |
43fe6a2a DS |
168 | } |
169 | ||
d8b87afe | 170 | uint32_t zebra_pbr_rules_hash_key(const void *arg) |
43fe6a2a | 171 | { |
d8b87afe | 172 | const struct zebra_pbr_rule *rule; |
43fe6a2a DS |
173 | uint32_t key; |
174 | ||
d8b87afe | 175 | rule = arg; |
5dd0722d PG |
176 | key = jhash_3words(rule->rule.seq, rule->rule.priority, |
177 | rule->rule.action.table, | |
178 | prefix_hash_key(&rule->rule.filter.src_ip)); | |
a0321978 | 179 | |
b94683f0 DS |
180 | key = jhash_3words(rule->rule.filter.fwmark, rule->vrf_id, |
181 | rule->rule.filter.ip_proto, key); | |
58a1d249 DS |
182 | |
183 | key = jhash(rule->ifname, strlen(rule->ifname), key); | |
7f0ea8a4 | 184 | |
5dd0722d PG |
185 | return jhash_3words(rule->rule.filter.src_port, |
186 | rule->rule.filter.dst_port, | |
187 | prefix_hash_key(&rule->rule.filter.dst_ip), | |
188 | jhash_1word(rule->rule.unique, key)); | |
43fe6a2a DS |
189 | } |
190 | ||
74df8d6d | 191 | bool zebra_pbr_rules_hash_equal(const void *arg1, const void *arg2) |
43fe6a2a DS |
192 | { |
193 | const struct zebra_pbr_rule *r1, *r2; | |
194 | ||
195 | r1 = (const struct zebra_pbr_rule *)arg1; | |
196 | r2 = (const struct zebra_pbr_rule *)arg2; | |
197 | ||
5dd0722d | 198 | if (r1->rule.seq != r2->rule.seq) |
74df8d6d | 199 | return false; |
43fe6a2a | 200 | |
5dd0722d | 201 | if (r1->rule.priority != r2->rule.priority) |
74df8d6d | 202 | return false; |
43fe6a2a | 203 | |
5dd0722d | 204 | if (r1->rule.unique != r2->rule.unique) |
74df8d6d | 205 | return false; |
b6c5d343 | 206 | |
5dd0722d | 207 | if (r1->rule.action.table != r2->rule.action.table) |
74df8d6d | 208 | return false; |
43fe6a2a | 209 | |
5dd0722d | 210 | if (r1->rule.filter.src_port != r2->rule.filter.src_port) |
74df8d6d | 211 | return false; |
43fe6a2a | 212 | |
5dd0722d | 213 | if (r1->rule.filter.dst_port != r2->rule.filter.dst_port) |
74df8d6d | 214 | return false; |
43fe6a2a | 215 | |
5dd0722d | 216 | if (r1->rule.filter.fwmark != r2->rule.filter.fwmark) |
74df8d6d | 217 | return false; |
b94683f0 DS |
218 | |
219 | if (r1->rule.filter.ip_proto != r2->rule.filter.ip_proto) | |
220 | return false; | |
1907e4b8 | 221 | |
5dd0722d | 222 | if (!prefix_same(&r1->rule.filter.src_ip, &r2->rule.filter.src_ip)) |
74df8d6d | 223 | return false; |
43fe6a2a | 224 | |
5dd0722d | 225 | if (!prefix_same(&r1->rule.filter.dst_ip, &r2->rule.filter.dst_ip)) |
74df8d6d | 226 | return false; |
43fe6a2a | 227 | |
58a1d249 | 228 | if (strcmp(r1->rule.ifname, r2->rule.ifname) != 0) |
74df8d6d | 229 | return false; |
a0321978 | 230 | |
7f0ea8a4 DS |
231 | if (r1->vrf_id != r2->vrf_id) |
232 | return false; | |
233 | ||
74df8d6d | 234 | return true; |
43fe6a2a DS |
235 | } |
236 | ||
f46bbab4 | 237 | struct pbr_rule_unique_lookup { |
8c3cd6c6 DS |
238 | struct zebra_pbr_rule *rule; |
239 | uint32_t unique; | |
58a1d249 | 240 | char ifname[INTERFACE_NAMSIZ + 1]; |
7f0ea8a4 | 241 | vrf_id_t vrf_id; |
8c3cd6c6 DS |
242 | }; |
243 | ||
e3b78da8 | 244 | static int pbr_rule_lookup_unique_walker(struct hash_bucket *b, void *data) |
8c3cd6c6 | 245 | { |
f46bbab4 | 246 | struct pbr_rule_unique_lookup *pul = data; |
8c3cd6c6 DS |
247 | struct zebra_pbr_rule *rule = b->data; |
248 | ||
7f0ea8a4 | 249 | if (pul->unique == rule->rule.unique |
58a1d249 | 250 | && strncmp(pul->ifname, rule->rule.ifname, INTERFACE_NAMSIZ) == 0 |
7f0ea8a4 | 251 | && pul->vrf_id == rule->vrf_id) { |
8c3cd6c6 DS |
252 | pul->rule = rule; |
253 | return HASHWALK_ABORT; | |
254 | } | |
255 | ||
256 | return HASHWALK_CONTINUE; | |
257 | } | |
258 | ||
62f20a52 DS |
259 | static struct zebra_pbr_rule * |
260 | pbr_rule_lookup_unique(struct zebra_pbr_rule *zrule) | |
8c3cd6c6 | 261 | { |
f46bbab4 | 262 | struct pbr_rule_unique_lookup pul; |
8c3cd6c6 | 263 | |
7f0ea8a4 | 264 | pul.unique = zrule->rule.unique; |
58a1d249 | 265 | strlcpy(pul.ifname, zrule->rule.ifname, INTERFACE_NAMSIZ); |
8c3cd6c6 | 266 | pul.rule = NULL; |
7f0ea8a4 DS |
267 | pul.vrf_id = zrule->vrf_id; |
268 | hash_walk(zrouter.rules_hash, &pbr_rule_lookup_unique_walker, &pul); | |
8c3cd6c6 DS |
269 | |
270 | return pul.rule; | |
271 | } | |
272 | ||
7661461a PG |
273 | void zebra_pbr_ipset_free(void *arg) |
274 | { | |
275 | struct zebra_pbr_ipset *ipset; | |
276 | ||
277 | ipset = (struct zebra_pbr_ipset *)arg; | |
1c6fca1f | 278 | hook_call(zebra_pbr_ipset_update, 0, ipset); |
c0ce4875 | 279 | XFREE(MTYPE_PBR_OBJ, ipset); |
7661461a PG |
280 | } |
281 | ||
d8b87afe | 282 | uint32_t zebra_pbr_ipset_hash_key(const void *arg) |
7661461a | 283 | { |
d8b87afe | 284 | const struct zebra_pbr_ipset *ipset = arg; |
425bdd6b | 285 | uint32_t *pnt = (uint32_t *)&ipset->ipset_name; |
62f20a52 | 286 | uint32_t key = jhash_1word(ipset->vrf_id, 0x63ab42de); |
7661461a | 287 | |
a60b7031 PG |
288 | key = jhash_1word(ipset->family, key); |
289 | ||
62f20a52 | 290 | return jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, key); |
7661461a PG |
291 | } |
292 | ||
74df8d6d | 293 | bool zebra_pbr_ipset_hash_equal(const void *arg1, const void *arg2) |
7661461a PG |
294 | { |
295 | const struct zebra_pbr_ipset *r1, *r2; | |
296 | ||
297 | r1 = (const struct zebra_pbr_ipset *)arg1; | |
298 | r2 = (const struct zebra_pbr_ipset *)arg2; | |
299 | ||
300 | if (r1->type != r2->type) | |
74df8d6d | 301 | return false; |
7661461a | 302 | if (r1->unique != r2->unique) |
74df8d6d | 303 | return false; |
62f20a52 DS |
304 | if (r1->vrf_id != r2->vrf_id) |
305 | return false; | |
a60b7031 PG |
306 | if (r1->family != r2->family) |
307 | return false; | |
62f20a52 | 308 | |
7661461a PG |
309 | if (strncmp(r1->ipset_name, r2->ipset_name, |
310 | ZEBRA_IPSET_NAME_SIZE)) | |
74df8d6d DS |
311 | return false; |
312 | return true; | |
7661461a PG |
313 | } |
314 | ||
315 | void zebra_pbr_ipset_entry_free(void *arg) | |
316 | { | |
317 | struct zebra_pbr_ipset_entry *ipset; | |
318 | ||
319 | ipset = (struct zebra_pbr_ipset_entry *)arg; | |
73a829f7 | 320 | |
1c6fca1f | 321 | hook_call(zebra_pbr_ipset_entry_update, 0, ipset); |
7661461a | 322 | |
c0ce4875 | 323 | XFREE(MTYPE_PBR_OBJ, ipset); |
7661461a PG |
324 | } |
325 | ||
d8b87afe | 326 | uint32_t zebra_pbr_ipset_entry_hash_key(const void *arg) |
7661461a | 327 | { |
d8b87afe | 328 | const struct zebra_pbr_ipset_entry *ipset; |
7661461a PG |
329 | uint32_t key; |
330 | ||
d8b87afe | 331 | ipset = arg; |
7661461a PG |
332 | key = prefix_hash_key(&ipset->src); |
333 | key = jhash_1word(ipset->unique, key); | |
334 | key = jhash_1word(prefix_hash_key(&ipset->dst), key); | |
25d760c5 PG |
335 | key = jhash(&ipset->dst_port_min, 2, key); |
336 | key = jhash(&ipset->dst_port_max, 2, key); | |
337 | key = jhash(&ipset->src_port_min, 2, key); | |
338 | key = jhash(&ipset->src_port_max, 2, key); | |
339 | key = jhash(&ipset->proto, 1, key); | |
7661461a PG |
340 | |
341 | return key; | |
342 | } | |
343 | ||
74df8d6d | 344 | bool zebra_pbr_ipset_entry_hash_equal(const void *arg1, const void *arg2) |
7661461a PG |
345 | { |
346 | const struct zebra_pbr_ipset_entry *r1, *r2; | |
347 | ||
348 | r1 = (const struct zebra_pbr_ipset_entry *)arg1; | |
349 | r2 = (const struct zebra_pbr_ipset_entry *)arg2; | |
350 | ||
351 | if (r1->unique != r2->unique) | |
74df8d6d | 352 | return false; |
7661461a PG |
353 | |
354 | if (!prefix_same(&r1->src, &r2->src)) | |
74df8d6d | 355 | return false; |
7661461a PG |
356 | |
357 | if (!prefix_same(&r1->dst, &r2->dst)) | |
74df8d6d | 358 | return false; |
7661461a | 359 | |
25d760c5 | 360 | if (r1->src_port_min != r2->src_port_min) |
74df8d6d | 361 | return false; |
25d760c5 PG |
362 | |
363 | if (r1->src_port_max != r2->src_port_max) | |
74df8d6d | 364 | return false; |
25d760c5 PG |
365 | |
366 | if (r1->dst_port_min != r2->dst_port_min) | |
74df8d6d | 367 | return false; |
25d760c5 PG |
368 | |
369 | if (r1->dst_port_max != r2->dst_port_max) | |
74df8d6d | 370 | return false; |
25d760c5 PG |
371 | |
372 | if (r1->proto != r2->proto) | |
74df8d6d DS |
373 | return false; |
374 | return true; | |
7661461a PG |
375 | } |
376 | ||
3b1de7b8 PG |
377 | /* this function gives option to flush plugin memory contexts |
378 | * with all parameter. set it to true to flush all | |
379 | * set it to false to flush only passed arg argument | |
380 | */ | |
381 | static void _zebra_pbr_iptable_free_all(void *arg, bool all) | |
7abd6c4f PG |
382 | { |
383 | struct zebra_pbr_iptable *iptable; | |
f80ec7e3 PG |
384 | struct listnode *node, *nnode; |
385 | char *name; | |
7abd6c4f PG |
386 | |
387 | iptable = (struct zebra_pbr_iptable *)arg; | |
3b1de7b8 PG |
388 | |
389 | if (all) | |
390 | hook_call(zebra_pbr_iptable_update, 0, iptable); | |
7abd6c4f | 391 | |
8b5c4dce QY |
392 | if (iptable->interface_name_list) { |
393 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, node, | |
394 | nnode, name)) { | |
395 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
396 | list_delete_node(iptable->interface_name_list, node); | |
397 | } | |
398 | list_delete(&iptable->interface_name_list); | |
f80ec7e3 | 399 | } |
c0ce4875 | 400 | XFREE(MTYPE_PBR_OBJ, iptable); |
7abd6c4f PG |
401 | } |
402 | ||
3b1de7b8 PG |
403 | void zebra_pbr_iptable_free(void *arg) |
404 | { | |
405 | _zebra_pbr_iptable_free_all(arg, false); | |
406 | } | |
407 | ||
d8b87afe | 408 | uint32_t zebra_pbr_iptable_hash_key(const void *arg) |
7abd6c4f | 409 | { |
d8b87afe | 410 | const struct zebra_pbr_iptable *iptable = arg; |
7abd6c4f PG |
411 | uint32_t *pnt = (uint32_t *)&(iptable->ipset_name); |
412 | uint32_t key; | |
413 | ||
414 | key = jhash2(pnt, ZEBRA_IPSET_NAME_HASH_SIZE, | |
415 | 0x63ab42de); | |
416 | key = jhash_1word(iptable->fwmark, key); | |
a60b7031 PG |
417 | key = jhash_1word(iptable->family, key); |
418 | key = jhash_1word(iptable->flow_label, key); | |
e7f7dad4 PG |
419 | key = jhash_1word(iptable->pkt_len_min, key); |
420 | key = jhash_1word(iptable->pkt_len_max, key); | |
dc993e76 PG |
421 | key = jhash_1word(iptable->tcp_flags, key); |
422 | key = jhash_1word(iptable->tcp_mask_flags, key); | |
4977bd6c | 423 | key = jhash_1word(iptable->dscp_value, key); |
f449d223 | 424 | key = jhash_1word(iptable->protocol, key); |
5ac5b7cc | 425 | key = jhash_1word(iptable->fragment, key); |
62f20a52 DS |
426 | key = jhash_1word(iptable->vrf_id, key); |
427 | ||
7abd6c4f PG |
428 | return jhash_3words(iptable->filter_bm, iptable->type, |
429 | iptable->unique, key); | |
430 | } | |
431 | ||
74df8d6d | 432 | bool zebra_pbr_iptable_hash_equal(const void *arg1, const void *arg2) |
7abd6c4f PG |
433 | { |
434 | const struct zebra_pbr_iptable *r1, *r2; | |
435 | ||
436 | r1 = (const struct zebra_pbr_iptable *)arg1; | |
437 | r2 = (const struct zebra_pbr_iptable *)arg2; | |
438 | ||
62f20a52 | 439 | if (r1->vrf_id != r2->vrf_id) |
b08047f8 | 440 | return false; |
7abd6c4f | 441 | if (r1->type != r2->type) |
74df8d6d | 442 | return false; |
7abd6c4f | 443 | if (r1->unique != r2->unique) |
74df8d6d | 444 | return false; |
7abd6c4f | 445 | if (r1->filter_bm != r2->filter_bm) |
74df8d6d | 446 | return false; |
7abd6c4f | 447 | if (r1->fwmark != r2->fwmark) |
74df8d6d | 448 | return false; |
7abd6c4f | 449 | if (r1->action != r2->action) |
74df8d6d | 450 | return false; |
7abd6c4f PG |
451 | if (strncmp(r1->ipset_name, r2->ipset_name, |
452 | ZEBRA_IPSET_NAME_SIZE)) | |
74df8d6d | 453 | return false; |
a60b7031 PG |
454 | if (r1->family != r2->family) |
455 | return false; | |
456 | if (r1->flow_label != r2->flow_label) | |
457 | return false; | |
e7f7dad4 | 458 | if (r1->pkt_len_min != r2->pkt_len_min) |
74df8d6d | 459 | return false; |
e7f7dad4 | 460 | if (r1->pkt_len_max != r2->pkt_len_max) |
74df8d6d | 461 | return false; |
dc993e76 | 462 | if (r1->tcp_flags != r2->tcp_flags) |
74df8d6d | 463 | return false; |
dc993e76 | 464 | if (r1->tcp_mask_flags != r2->tcp_mask_flags) |
74df8d6d | 465 | return false; |
4977bd6c | 466 | if (r1->dscp_value != r2->dscp_value) |
74df8d6d | 467 | return false; |
5ac5b7cc | 468 | if (r1->fragment != r2->fragment) |
74df8d6d | 469 | return false; |
f449d223 PG |
470 | if (r1->protocol != r2->protocol) |
471 | return false; | |
74df8d6d | 472 | return true; |
7abd6c4f PG |
473 | } |
474 | ||
43fe6a2a DS |
475 | static void *pbr_rule_alloc_intern(void *arg) |
476 | { | |
477 | struct zebra_pbr_rule *zpr; | |
478 | struct zebra_pbr_rule *new; | |
479 | ||
480 | zpr = (struct zebra_pbr_rule *)arg; | |
481 | ||
c0ce4875 | 482 | new = XCALLOC(MTYPE_PBR_OBJ, sizeof(*new)); |
43fe6a2a DS |
483 | |
484 | memcpy(new, zpr, sizeof(*zpr)); | |
485 | ||
486 | return new; | |
487 | } | |
488 | ||
59f47eb0 AK |
489 | static struct zebra_pbr_rule *pbr_rule_free(struct zebra_pbr_rule *hash_data, |
490 | bool free_data) | |
491 | { | |
492 | if (hash_data->action.neigh) | |
493 | zebra_neigh_deref(hash_data); | |
494 | hash_release(zrouter.rules_hash, hash_data); | |
495 | if (free_data) { | |
c0ce4875 | 496 | XFREE(MTYPE_PBR_OBJ, hash_data); |
59f47eb0 AK |
497 | return NULL; |
498 | } | |
499 | ||
500 | return hash_data; | |
501 | } | |
502 | ||
503 | static struct zebra_pbr_rule *pbr_rule_release(struct zebra_pbr_rule *rule, | |
504 | bool free_data) | |
3ae327cb SW |
505 | { |
506 | struct zebra_pbr_rule *lookup; | |
507 | ||
508 | lookup = hash_lookup(zrouter.rules_hash, rule); | |
509 | ||
510 | if (!lookup) | |
59f47eb0 | 511 | return NULL; |
3ae327cb | 512 | |
59f47eb0 AK |
513 | return pbr_rule_free(lookup, free_data); |
514 | } | |
3ae327cb | 515 | |
59f47eb0 AK |
516 | void zebra_pbr_show_rule_unit(struct zebra_pbr_rule *rule, struct vty *vty) |
517 | { | |
518 | struct pbr_rule *prule = &rule->rule; | |
519 | struct zebra_pbr_action *zaction = &rule->action; | |
520 | ||
521 | vty_out(vty, "Rules if %s\n", rule->ifname); | |
522 | vty_out(vty, " Seq %u pri %u\n", prule->seq, prule->priority); | |
523 | if (prule->filter.filter_bm & PBR_FILTER_SRC_IP) | |
524 | vty_out(vty, " SRC IP Match: %pFX\n", &prule->filter.src_ip); | |
525 | if (prule->filter.filter_bm & PBR_FILTER_DST_IP) | |
526 | vty_out(vty, " DST IP Match: %pFX\n", &prule->filter.dst_ip); | |
527 | if (prule->filter.filter_bm & PBR_FILTER_IP_PROTOCOL) | |
528 | vty_out(vty, " IP protocol Match: %u\n", | |
529 | prule->filter.ip_proto); | |
530 | if (prule->filter.filter_bm & PBR_FILTER_SRC_PORT) | |
531 | vty_out(vty, " SRC Port Match: %u\n", prule->filter.src_port); | |
532 | if (prule->filter.filter_bm & PBR_FILTER_DST_PORT) | |
533 | vty_out(vty, " DST Port Match: %u\n", prule->filter.dst_port); | |
534 | ||
535 | if (prule->filter.filter_bm & PBR_FILTER_DSFIELD) { | |
536 | vty_out(vty, " DSCP Match: %u\n", | |
537 | (prule->filter.dsfield & PBR_DSFIELD_DSCP) >> 2); | |
538 | vty_out(vty, " ECN Match: %u\n", | |
539 | prule->filter.dsfield & PBR_DSFIELD_ECN); | |
540 | } | |
541 | ||
542 | if (prule->filter.filter_bm & PBR_FILTER_FWMARK) | |
543 | vty_out(vty, " MARK Match: %u\n", prule->filter.fwmark); | |
544 | ||
545 | vty_out(vty, " Tableid: %u\n", prule->action.table); | |
546 | if (zaction->afi == AFI_IP) | |
547 | vty_out(vty, " Action: nh: %pI4 intf: %s\n", | |
548 | &zaction->gate.ipv4, | |
549 | ifindex2ifname(zaction->ifindex, rule->vrf_id)); | |
550 | if (zaction->afi == AFI_IP6) | |
551 | vty_out(vty, " Action: nh: %pI6 intf: %s\n", | |
552 | &zaction->gate.ipv6, | |
553 | ifindex2ifname(zaction->ifindex, rule->vrf_id)); | |
554 | if (zaction->neigh && (zaction->neigh->flags & ZEBRA_NEIGH_ENT_ACTIVE)) | |
555 | vty_out(vty, " Action: mac: %pEA\n", &zaction->neigh->mac); | |
556 | } | |
557 | ||
558 | static int zebra_pbr_show_rules_walkcb(struct hash_bucket *bucket, void *arg) | |
559 | { | |
560 | struct zebra_pbr_rule *rule = (struct zebra_pbr_rule *)bucket->data; | |
561 | struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; | |
562 | struct vty *vty = env->vty; | |
563 | ||
564 | zebra_pbr_show_rule_unit(rule, vty); | |
565 | ||
566 | return HASHWALK_CONTINUE; | |
567 | } | |
568 | ||
569 | void zebra_pbr_show_rule(struct vty *vty) | |
570 | { | |
571 | struct zebra_pbr_env_display env; | |
572 | ||
573 | env.vty = vty; | |
574 | hash_walk(zrouter.rules_hash, zebra_pbr_show_rules_walkcb, &env); | |
575 | } | |
576 | ||
577 | void zebra_pbr_config_write(struct vty *vty) | |
578 | { | |
579 | if (zebra_pbr_expand_action) | |
580 | vty_out(vty, "pbr nexthop-resolve\n"); | |
581 | } | |
582 | ||
583 | void zebra_pbr_expand_action_update(bool enable) | |
584 | { | |
585 | zebra_pbr_expand_action = enable; | |
586 | } | |
587 | ||
588 | static void zebra_pbr_expand_rule(struct zebra_pbr_rule *rule) | |
589 | { | |
590 | struct prefix p; | |
591 | struct route_table *table; | |
592 | struct route_node *rn; | |
593 | rib_dest_t *dest; | |
594 | struct route_entry *re; | |
595 | const struct nexthop_group *nhg; | |
596 | const struct nexthop *nexthop; | |
597 | struct zebra_pbr_action *action = &rule->action; | |
598 | struct ipaddr ip; | |
599 | ||
600 | if (!zebra_pbr_expand_action) | |
601 | return; | |
602 | ||
603 | table = zebra_vrf_get_table_with_table_id( | |
604 | AFI_IP, SAFI_UNICAST, VRF_DEFAULT, rule->rule.action.table); | |
605 | if (!table) | |
606 | return; | |
607 | ||
608 | memset(&p, 0, sizeof(p)); | |
609 | p.family = AF_INET; | |
610 | ||
611 | rn = route_node_lookup(table, &p); | |
612 | if (!rn) | |
613 | return; | |
614 | ||
615 | dest = rib_dest_from_rnode(rn); | |
616 | re = dest->selected_fib; | |
617 | if (!re) { | |
618 | route_unlock_node(rn); | |
619 | return; | |
620 | } | |
621 | ||
622 | nhg = rib_get_fib_nhg(re); | |
623 | if (!nhg) { | |
624 | route_unlock_node(rn); | |
625 | return; | |
626 | } | |
627 | ||
628 | nexthop = nhg->nexthop; | |
629 | if (nexthop) { | |
630 | switch (nexthop->type) { | |
631 | case NEXTHOP_TYPE_IPV4: | |
632 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
633 | action->afi = AFI_IP; | |
634 | action->gate.ipv4 = nexthop->gate.ipv4; | |
635 | action->ifindex = nexthop->ifindex; | |
636 | ip.ipa_type = AF_INET; | |
637 | ip.ipaddr_v4 = action->gate.ipv4; | |
638 | zebra_neigh_ref(action->ifindex, &ip, rule); | |
639 | break; | |
640 | ||
641 | case NEXTHOP_TYPE_IPV6: | |
642 | case NEXTHOP_TYPE_IPV6_IFINDEX: | |
643 | action->afi = AFI_IP6; | |
644 | action->gate.ipv6 = nexthop->gate.ipv6; | |
645 | action->ifindex = nexthop->ifindex; | |
646 | ip.ipa_type = AF_INET6; | |
647 | ip.ipaddr_v6 = action->gate.ipv6; | |
648 | zebra_neigh_ref(action->ifindex, &ip, rule); | |
649 | break; | |
650 | ||
651 | default: | |
652 | action->afi = AFI_UNSPEC; | |
653 | } | |
654 | } | |
655 | ||
656 | route_unlock_node(rn); | |
3ae327cb SW |
657 | } |
658 | ||
7f0ea8a4 | 659 | void zebra_pbr_add_rule(struct zebra_pbr_rule *rule) |
43fe6a2a | 660 | { |
3ae327cb | 661 | struct zebra_pbr_rule *found; |
59f47eb0 AK |
662 | struct zebra_pbr_rule *old; |
663 | struct zebra_pbr_rule *new; | |
8c3cd6c6 | 664 | |
3ae327cb SW |
665 | /** |
666 | * Check if we already have it (this checks via a unique ID, walking | |
667 | * over the hash table, not via a hash operation). | |
8c3cd6c6 | 668 | */ |
3ae327cb SW |
669 | found = pbr_rule_lookup_unique(rule); |
670 | ||
3ae327cb SW |
671 | /* If found, this is an update */ |
672 | if (found) { | |
8eeca5a2 SW |
673 | if (IS_ZEBRA_DEBUG_PBR) |
674 | zlog_debug( | |
675 | "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- update", | |
676 | __func__, rule->rule.seq, rule->rule.priority, | |
677 | rule->rule.unique, rule->rule.ifname); | |
678 | ||
59f47eb0 AK |
679 | /* remove the old entry from the hash but don't free the hash |
680 | * data yet as we need it for the dplane update | |
681 | */ | |
682 | old = pbr_rule_release(found, false); | |
683 | ||
684 | /* insert new entry into hash */ | |
685 | new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern); | |
686 | /* expand the action if needed */ | |
687 | zebra_pbr_expand_rule(new); | |
688 | /* update dataplane */ | |
689 | (void)dplane_pbr_rule_update(found, new); | |
690 | /* release the old hash data */ | |
691 | if (old) | |
c0ce4875 | 692 | XFREE(MTYPE_PBR_OBJ, old); |
8eeca5a2 SW |
693 | } else { |
694 | if (IS_ZEBRA_DEBUG_PBR) | |
695 | zlog_debug( | |
696 | "%s: seq: %d, prior: %d, unique: %d, ifname: %s -- new", | |
697 | __func__, rule->rule.seq, rule->rule.priority, | |
698 | rule->rule.unique, rule->rule.ifname); | |
699 | ||
59f47eb0 AK |
700 | /* insert new entry into hash */ |
701 | new = hash_get(zrouter.rules_hash, rule, pbr_rule_alloc_intern); | |
702 | /* expand the action if needed */ | |
703 | zebra_pbr_expand_rule(new); | |
704 | (void)dplane_pbr_rule_add(new); | |
8eeca5a2 | 705 | } |
f7692085 | 706 | |
1fbfe5a5 DS |
707 | } |
708 | ||
7f0ea8a4 | 709 | void zebra_pbr_del_rule(struct zebra_pbr_rule *rule) |
1fbfe5a5 | 710 | { |
8eeca5a2 SW |
711 | if (IS_ZEBRA_DEBUG_PBR) |
712 | zlog_debug("%s: seq: %d, prior: %d, unique: %d, ifname: %s", | |
713 | __func__, rule->rule.seq, rule->rule.priority, | |
714 | rule->rule.unique, rule->rule.ifname); | |
715 | ||
f62e5480 | 716 | (void)dplane_pbr_rule_delete(rule); |
43fe6a2a | 717 | |
59f47eb0 | 718 | if (pbr_rule_release(rule, true)) |
9df414fe | 719 | zlog_debug("%s: Rule being deleted we know nothing about", |
15569c58 | 720 | __func__); |
1fbfe5a5 DS |
721 | } |
722 | ||
5162e000 PG |
723 | void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx) |
724 | { | |
725 | int mode, ret = 0; | |
726 | struct zebra_pbr_iptable ipt; | |
727 | ||
728 | if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPTABLE_ADD) | |
729 | mode = 1; | |
730 | else | |
731 | mode = 0; | |
732 | ||
8d78e148 DS |
733 | dplane_ctx_get_pbr_iptable(ctx, &ipt); |
734 | ||
735 | ret = hook_call(zebra_pbr_iptable_update, mode, &ipt); | |
736 | if (ret) | |
737 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); | |
738 | else | |
5162e000 PG |
739 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); |
740 | } | |
741 | ||
ef524230 PG |
742 | void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx) |
743 | { | |
744 | int mode, ret = 0; | |
745 | struct zebra_pbr_ipset ipset; | |
746 | ||
747 | if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ADD) | |
748 | mode = 1; | |
749 | else | |
750 | mode = 0; | |
8249f96a DS |
751 | |
752 | dplane_ctx_get_pbr_ipset(ctx, &ipset); | |
753 | ||
754 | ret = hook_call(zebra_pbr_ipset_update, mode, &ipset); | |
755 | if (ret) | |
756 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); | |
757 | else | |
ef524230 PG |
758 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); |
759 | } | |
760 | ||
761 | void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx) | |
762 | { | |
763 | int mode, ret = 0; | |
764 | struct zebra_pbr_ipset_entry ipset_entry; | |
765 | struct zebra_pbr_ipset ipset; | |
766 | ||
767 | if (dplane_ctx_get_op(ctx) == DPLANE_OP_IPSET_ENTRY_ADD) | |
768 | mode = 1; | |
769 | else | |
770 | mode = 0; | |
771 | ||
f284c132 | 772 | dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry); |
8249f96a DS |
773 | dplane_ctx_get_pbr_ipset(ctx, &ipset); |
774 | ||
ef524230 PG |
775 | ipset_entry.backpointer = &ipset; |
776 | ||
777 | ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry); | |
778 | if (ret) | |
779 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); | |
780 | else | |
781 | dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); | |
782 | } | |
783 | ||
e3b78da8 | 784 | static void zebra_pbr_cleanup_rules(struct hash_bucket *b, void *data) |
e69aa084 | 785 | { |
e69aa084 DS |
786 | struct zebra_pbr_rule *rule = b->data; |
787 | int *sock = data; | |
788 | ||
789 | if (rule->sock == *sock) { | |
f62e5480 | 790 | (void)dplane_pbr_rule_delete(rule); |
59f47eb0 | 791 | pbr_rule_free(rule, true); |
e69aa084 DS |
792 | } |
793 | } | |
794 | ||
e3b78da8 | 795 | static void zebra_pbr_cleanup_ipset(struct hash_bucket *b, void *data) |
c2ef5232 | 796 | { |
c2ef5232 PG |
797 | struct zebra_pbr_ipset *ipset = b->data; |
798 | int *sock = data; | |
799 | ||
73a829f7 | 800 | if (ipset->sock == *sock) { |
b147e204 QY |
801 | if (hash_release(zrouter.ipset_hash, ipset)) |
802 | zebra_pbr_ipset_free(ipset); | |
803 | else | |
804 | hook_call(zebra_pbr_ipset_update, 0, ipset); | |
73a829f7 | 805 | } |
c2ef5232 PG |
806 | } |
807 | ||
e3b78da8 | 808 | static void zebra_pbr_cleanup_ipset_entry(struct hash_bucket *b, void *data) |
c2ef5232 | 809 | { |
c2ef5232 PG |
810 | struct zebra_pbr_ipset_entry *ipset = b->data; |
811 | int *sock = data; | |
812 | ||
73a829f7 | 813 | if (ipset->sock == *sock) { |
b147e204 QY |
814 | if (hash_release(zrouter.ipset_entry_hash, ipset)) |
815 | zebra_pbr_ipset_entry_free(ipset); | |
816 | else | |
817 | hook_call(zebra_pbr_ipset_entry_update, 0, ipset); | |
73a829f7 | 818 | } |
c2ef5232 PG |
819 | } |
820 | ||
e3b78da8 | 821 | static void zebra_pbr_cleanup_iptable(struct hash_bucket *b, void *data) |
c2ef5232 | 822 | { |
c2ef5232 PG |
823 | struct zebra_pbr_iptable *iptable = b->data; |
824 | int *sock = data; | |
825 | ||
73a829f7 | 826 | if (iptable->sock == *sock) { |
b147e204 | 827 | if (hash_release(zrouter.iptable_hash, iptable)) |
3b1de7b8 | 828 | _zebra_pbr_iptable_free_all(iptable, true); |
b147e204 QY |
829 | else |
830 | hook_call(zebra_pbr_iptable_update, 0, iptable); | |
73a829f7 | 831 | } |
c2ef5232 PG |
832 | } |
833 | ||
4c0ec639 | 834 | static int zebra_pbr_client_close_cleanup(struct zserv *client) |
e69aa084 | 835 | { |
4c0ec639 | 836 | int sock = client->sock; |
e69aa084 | 837 | |
4c0ec639 PG |
838 | if (!sock) |
839 | return 0; | |
7f0ea8a4 | 840 | hash_iterate(zrouter.rules_hash, zebra_pbr_cleanup_rules, &sock); |
62f20a52 DS |
841 | hash_iterate(zrouter.iptable_hash, zebra_pbr_cleanup_iptable, &sock); |
842 | hash_iterate(zrouter.ipset_entry_hash, zebra_pbr_cleanup_ipset_entry, | |
843 | &sock); | |
844 | hash_iterate(zrouter.ipset_hash, zebra_pbr_cleanup_ipset, &sock); | |
4c0ec639 PG |
845 | return 1; |
846 | } | |
847 | ||
848 | void zebra_pbr_init(void) | |
849 | { | |
c0ea1ae7 | 850 | hook_register(zserv_client_close, zebra_pbr_client_close_cleanup); |
e69aa084 DS |
851 | } |
852 | ||
7661461a PG |
853 | static void *pbr_ipset_alloc_intern(void *arg) |
854 | { | |
855 | struct zebra_pbr_ipset *zpi; | |
856 | struct zebra_pbr_ipset *new; | |
857 | ||
858 | zpi = (struct zebra_pbr_ipset *)arg; | |
859 | ||
c0ce4875 | 860 | new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset)); |
7661461a PG |
861 | |
862 | memcpy(new, zpi, sizeof(*zpi)); | |
863 | ||
864 | return new; | |
865 | } | |
866 | ||
62f20a52 | 867 | void zebra_pbr_create_ipset(struct zebra_pbr_ipset *ipset) |
7661461a | 868 | { |
62f20a52 | 869 | (void)hash_get(zrouter.ipset_hash, ipset, pbr_ipset_alloc_intern); |
ef524230 | 870 | (void)dplane_pbr_ipset_add(ipset); |
7661461a PG |
871 | } |
872 | ||
62f20a52 | 873 | void zebra_pbr_destroy_ipset(struct zebra_pbr_ipset *ipset) |
7661461a PG |
874 | { |
875 | struct zebra_pbr_ipset *lookup; | |
876 | ||
62f20a52 | 877 | lookup = hash_lookup(zrouter.ipset_hash, ipset); |
ef524230 | 878 | (void)dplane_pbr_ipset_delete(ipset); |
de67547d | 879 | if (lookup) { |
62f20a52 | 880 | hash_release(zrouter.ipset_hash, lookup); |
c0ce4875 | 881 | XFREE(MTYPE_PBR_OBJ, lookup); |
de67547d | 882 | } else |
9df414fe QY |
883 | zlog_debug( |
884 | "%s: IPSet Entry being deleted we know nothing about", | |
15569c58 | 885 | __func__); |
7661461a PG |
886 | } |
887 | ||
ed78b7c8 PG |
888 | struct pbr_ipset_name_lookup { |
889 | struct zebra_pbr_ipset *ipset; | |
890 | char ipset_name[ZEBRA_IPSET_NAME_SIZE]; | |
891 | }; | |
892 | ||
5b0d92b8 | 893 | const char *zebra_pbr_ipset_type2str(uint32_t type) |
586f4ccf PG |
894 | { |
895 | return lookup_msg(ipset_type_msg, type, | |
896 | "Unrecognized IPset Type"); | |
897 | } | |
898 | ||
e3b78da8 | 899 | static int zebra_pbr_ipset_pername_walkcb(struct hash_bucket *bucket, void *arg) |
ed78b7c8 PG |
900 | { |
901 | struct pbr_ipset_name_lookup *pinl = | |
902 | (struct pbr_ipset_name_lookup *)arg; | |
e3b78da8 | 903 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; |
ed78b7c8 PG |
904 | |
905 | if (!strncmp(pinl->ipset_name, zpi->ipset_name, | |
906 | ZEBRA_IPSET_NAME_SIZE)) { | |
907 | pinl->ipset = zpi; | |
908 | return HASHWALK_ABORT; | |
909 | } | |
910 | return HASHWALK_CONTINUE; | |
911 | } | |
912 | ||
62f20a52 | 913 | struct zebra_pbr_ipset *zebra_pbr_lookup_ipset_pername(char *ipsetname) |
d59c13af | 914 | { |
ed78b7c8 PG |
915 | struct pbr_ipset_name_lookup pinl; |
916 | struct pbr_ipset_name_lookup *ptr = &pinl; | |
917 | ||
d59c13af PG |
918 | if (!ipsetname) |
919 | return NULL; | |
ed78b7c8 PG |
920 | memset(ptr, 0, sizeof(struct pbr_ipset_name_lookup)); |
921 | snprintf((char *)ptr->ipset_name, ZEBRA_IPSET_NAME_SIZE, "%s", | |
922 | ipsetname); | |
62f20a52 | 923 | hash_walk(zrouter.ipset_hash, zebra_pbr_ipset_pername_walkcb, ptr); |
ed78b7c8 | 924 | return ptr->ipset; |
d59c13af PG |
925 | } |
926 | ||
7661461a PG |
927 | static void *pbr_ipset_entry_alloc_intern(void *arg) |
928 | { | |
929 | struct zebra_pbr_ipset_entry *zpi; | |
930 | struct zebra_pbr_ipset_entry *new; | |
931 | ||
932 | zpi = (struct zebra_pbr_ipset_entry *)arg; | |
933 | ||
c0ce4875 | 934 | new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_ipset_entry)); |
7661461a PG |
935 | |
936 | memcpy(new, zpi, sizeof(*zpi)); | |
937 | ||
938 | return new; | |
939 | } | |
940 | ||
62f20a52 | 941 | void zebra_pbr_add_ipset_entry(struct zebra_pbr_ipset_entry *ipset) |
7661461a | 942 | { |
62f20a52 | 943 | (void)hash_get(zrouter.ipset_entry_hash, ipset, |
7661461a | 944 | pbr_ipset_entry_alloc_intern); |
ef524230 | 945 | (void)dplane_pbr_ipset_entry_add(ipset); |
7661461a PG |
946 | } |
947 | ||
62f20a52 | 948 | void zebra_pbr_del_ipset_entry(struct zebra_pbr_ipset_entry *ipset) |
7661461a PG |
949 | { |
950 | struct zebra_pbr_ipset_entry *lookup; | |
951 | ||
62f20a52 | 952 | lookup = hash_lookup(zrouter.ipset_entry_hash, ipset); |
ef524230 | 953 | (void)dplane_pbr_ipset_entry_delete(ipset); |
de67547d | 954 | if (lookup) { |
62f20a52 | 955 | hash_release(zrouter.ipset_entry_hash, lookup); |
c0ce4875 | 956 | XFREE(MTYPE_PBR_OBJ, lookup); |
de67547d | 957 | } else |
9df414fe | 958 | zlog_debug("%s: IPSet being deleted we know nothing about", |
15569c58 | 959 | __func__); |
7661461a PG |
960 | } |
961 | ||
7abd6c4f PG |
962 | static void *pbr_iptable_alloc_intern(void *arg) |
963 | { | |
964 | struct zebra_pbr_iptable *zpi; | |
965 | struct zebra_pbr_iptable *new; | |
592af4cc QY |
966 | struct listnode *ln; |
967 | char *ifname; | |
7abd6c4f PG |
968 | |
969 | zpi = (struct zebra_pbr_iptable *)arg; | |
970 | ||
c0ce4875 | 971 | new = XCALLOC(MTYPE_PBR_OBJ, sizeof(struct zebra_pbr_iptable)); |
7abd6c4f | 972 | |
592af4cc | 973 | /* Deep structure copy */ |
7abd6c4f | 974 | memcpy(new, zpi, sizeof(*zpi)); |
592af4cc QY |
975 | new->interface_name_list = list_new(); |
976 | ||
977 | if (zpi->interface_name_list) { | |
978 | for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname)) | |
979 | listnode_add(new->interface_name_list, | |
980 | XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname)); | |
981 | } | |
7abd6c4f PG |
982 | |
983 | return new; | |
984 | } | |
985 | ||
62f20a52 | 986 | void zebra_pbr_add_iptable(struct zebra_pbr_iptable *iptable) |
7abd6c4f | 987 | { |
c9250e28 PG |
988 | struct zebra_pbr_iptable *ipt_hash; |
989 | ||
990 | ipt_hash = hash_get(zrouter.iptable_hash, iptable, | |
991 | pbr_iptable_alloc_intern); | |
992 | (void)dplane_pbr_iptable_add(ipt_hash); | |
7abd6c4f PG |
993 | } |
994 | ||
62f20a52 | 995 | void zebra_pbr_del_iptable(struct zebra_pbr_iptable *iptable) |
7abd6c4f | 996 | { |
f80ec7e3 | 997 | struct zebra_pbr_iptable *lookup; |
7abd6c4f | 998 | |
62f20a52 | 999 | lookup = hash_lookup(zrouter.iptable_hash, iptable); |
5162e000 | 1000 | (void)dplane_pbr_iptable_delete(iptable); |
f80ec7e3 PG |
1001 | if (lookup) { |
1002 | struct listnode *node, *nnode; | |
1003 | char *name; | |
1004 | ||
62f20a52 | 1005 | hash_release(zrouter.iptable_hash, lookup); |
f80ec7e3 PG |
1006 | for (ALL_LIST_ELEMENTS(iptable->interface_name_list, |
1007 | node, nnode, name)) { | |
1008 | XFREE(MTYPE_PBR_IPTABLE_IFNAME, name); | |
1009 | list_delete_node(iptable->interface_name_list, | |
1010 | node); | |
1011 | } | |
8b5c4dce | 1012 | list_delete(&iptable->interface_name_list); |
c0ce4875 | 1013 | XFREE(MTYPE_PBR_OBJ, lookup); |
f80ec7e3 | 1014 | } else |
9df414fe | 1015 | zlog_debug("%s: IPTable being deleted we know nothing about", |
5e81f5dd | 1016 | __func__); |
7abd6c4f PG |
1017 | } |
1018 | ||
942bf97b | 1019 | /* |
1020 | * Handle success or failure of rule (un)install in the kernel. | |
1021 | */ | |
f62e5480 JU |
1022 | void zebra_pbr_dplane_result(struct zebra_dplane_ctx *ctx) |
1023 | { | |
1024 | enum zebra_dplane_result res; | |
1025 | enum dplane_op_e op; | |
1026 | ||
1027 | res = dplane_ctx_get_status(ctx); | |
1028 | op = dplane_ctx_get_op(ctx); | |
1029 | if (op == DPLANE_OP_RULE_ADD || op == DPLANE_OP_RULE_UPDATE) | |
1030 | zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1031 | ? ZAPI_RULE_INSTALLED | |
1032 | : ZAPI_RULE_FAIL_INSTALL); | |
1033 | else if (op == DPLANE_OP_RULE_DELETE) | |
1034 | zsend_rule_notify_owner(ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1035 | ? ZAPI_RULE_REMOVED | |
1036 | : ZAPI_RULE_FAIL_REMOVE); | |
5162e000 PG |
1037 | else if (op == DPLANE_OP_IPTABLE_ADD) |
1038 | zsend_iptable_notify_owner(ctx, | |
1039 | res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1040 | ? ZAPI_IPTABLE_INSTALLED | |
1041 | : ZAPI_IPTABLE_FAIL_INSTALL); | |
1042 | else if (op == DPLANE_OP_IPTABLE_DELETE) | |
1043 | zsend_iptable_notify_owner(ctx, | |
1044 | res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1045 | ? ZAPI_IPTABLE_REMOVED | |
1046 | : ZAPI_IPTABLE_FAIL_REMOVE); | |
ef524230 PG |
1047 | else if (op == DPLANE_OP_IPSET_ADD) |
1048 | zsend_ipset_notify_owner(ctx, | |
1049 | res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1050 | ? ZAPI_IPSET_INSTALLED | |
1051 | : ZAPI_IPSET_FAIL_INSTALL); | |
1052 | else if (op == DPLANE_OP_IPSET_DELETE) | |
1053 | zsend_ipset_notify_owner(ctx, | |
1054 | res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1055 | ? ZAPI_IPSET_REMOVED | |
1056 | : ZAPI_IPSET_FAIL_REMOVE); | |
1057 | else if (op == DPLANE_OP_IPSET_ENTRY_ADD) | |
1058 | zsend_ipset_entry_notify_owner( | |
1059 | ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1060 | ? ZAPI_IPSET_ENTRY_INSTALLED | |
1061 | : ZAPI_IPSET_ENTRY_FAIL_INSTALL); | |
1062 | else if (op == DPLANE_OP_IPSET_ENTRY_DELETE) | |
1063 | zsend_ipset_entry_notify_owner( | |
1064 | ctx, res == ZEBRA_DPLANE_REQUEST_SUCCESS | |
1065 | ? ZAPI_IPSET_ENTRY_REMOVED | |
1066 | : ZAPI_IPSET_ENTRY_FAIL_REMOVE); | |
f62e5480 JU |
1067 | else |
1068 | flog_err( | |
1069 | EC_ZEBRA_PBR_RULE_UPDATE, | |
1070 | "Context received in pbr rule dplane result handler with incorrect OP code (%u)", | |
1071 | op); | |
942bf97b | 1072 | } |
1073 | ||
1074 | /* | |
1075 | * Handle rule delete notification from kernel. | |
1076 | */ | |
a0321978 | 1077 | int kernel_pbr_rule_del(struct zebra_pbr_rule *rule) |
942bf97b | 1078 | { |
1079 | return 0; | |
1080 | } | |
586f4ccf PG |
1081 | |
1082 | struct zebra_pbr_ipset_entry_unique_display { | |
1083 | struct zebra_pbr_ipset *zpi; | |
1084 | struct vty *vty; | |
73a829f7 | 1085 | struct zebra_ns *zns; |
586f4ccf PG |
1086 | }; |
1087 | ||
586f4ccf PG |
1088 | |
1089 | static const char *zebra_pbr_prefix2str(union prefixconstptr pu, | |
1090 | char *str, int size) | |
1091 | { | |
1092 | const struct prefix *p = pu.p; | |
1093 | char buf[PREFIX2STR_BUFFER]; | |
1094 | ||
936fbaef | 1095 | if ((p->family == AF_INET && p->prefixlen == IPV4_MAX_BITLEN) |
f4d81e55 | 1096 | || (p->family == AF_INET6 && p->prefixlen == IPV6_MAX_BITLEN)) { |
586f4ccf PG |
1097 | snprintf(str, size, "%s", inet_ntop(p->family, &p->u.prefix, |
1098 | buf, PREFIX2STR_BUFFER)); | |
1099 | return str; | |
1100 | } | |
1101 | return prefix2str(pu, str, size); | |
1102 | } | |
1103 | ||
be729dd7 PG |
1104 | static void zebra_pbr_display_icmp(struct vty *vty, |
1105 | struct zebra_pbr_ipset_entry *zpie) | |
1106 | { | |
1107 | char decoded_str[20]; | |
1108 | uint16_t port; | |
c9b1139a PG |
1109 | struct zebra_pbr_ipset *zpi; |
1110 | ||
1111 | zpi = zpie->backpointer; | |
be729dd7 PG |
1112 | |
1113 | /* range icmp type */ | |
1114 | if (zpie->src_port_max || zpie->dst_port_max) { | |
2b7165e7 | 1115 | vty_out(vty, ":icmp:[type <%u:%u>;code <%u:%u>", |
be729dd7 PG |
1116 | zpie->src_port_min, zpie->src_port_max, |
1117 | zpie->dst_port_min, zpie->dst_port_max); | |
1118 | } else { | |
1119 | port = ((zpie->src_port_min << 8) & 0xff00) + | |
1120 | (zpie->dst_port_min & 0xff); | |
1121 | memset(decoded_str, 0, sizeof(decoded_str)); | |
2b7165e7 | 1122 | snprintf(decoded_str, sizeof(decoded_str), "%u/%u", |
772270f3 | 1123 | zpie->src_port_min, zpie->dst_port_min); |
c9b1139a PG |
1124 | vty_out(vty, ":%s:%s", |
1125 | zpi->family == AF_INET6 ? "ipv6-icmp" : "icmp", | |
1126 | lookup_msg(zpi->family == AF_INET6 ? | |
1127 | icmpv6_typecode_str : icmp_typecode_str, | |
be729dd7 PG |
1128 | port, decoded_str)); |
1129 | } | |
1130 | } | |
1131 | ||
25d760c5 PG |
1132 | static void zebra_pbr_display_port(struct vty *vty, uint32_t filter_bm, |
1133 | uint16_t port_min, uint16_t port_max, | |
1134 | uint8_t proto) | |
1135 | { | |
1136 | if (!(filter_bm & PBR_FILTER_PROTO)) { | |
1137 | if (port_max) | |
1138 | vty_out(vty, ":udp/tcp:%d-%d", | |
1139 | port_min, port_max); | |
1140 | else | |
1141 | vty_out(vty, ":udp/tcp:%d", | |
1142 | port_min); | |
1143 | } else { | |
1144 | if (port_max) | |
1145 | vty_out(vty, ":proto %d:%d-%d", | |
1146 | proto, port_min, port_max); | |
1147 | else | |
1148 | vty_out(vty, ":proto %d:%d", | |
1149 | proto, port_min); | |
1150 | } | |
1151 | } | |
1152 | ||
e3b78da8 | 1153 | static int zebra_pbr_show_ipset_entry_walkcb(struct hash_bucket *bucket, |
586f4ccf PG |
1154 | void *arg) |
1155 | { | |
1156 | struct zebra_pbr_ipset_entry_unique_display *unique = | |
1157 | (struct zebra_pbr_ipset_entry_unique_display *)arg; | |
1158 | struct zebra_pbr_ipset *zpi = unique->zpi; | |
1159 | struct vty *vty = unique->vty; | |
1160 | struct zebra_pbr_ipset_entry *zpie = | |
e3b78da8 | 1161 | (struct zebra_pbr_ipset_entry *)bucket->data; |
73a829f7 | 1162 | uint64_t pkts = 0, bytes = 0; |
73a829f7 | 1163 | int ret = 0; |
586f4ccf PG |
1164 | |
1165 | if (zpie->backpointer != zpi) | |
1166 | return HASHWALK_CONTINUE; | |
1167 | ||
25d760c5 PG |
1168 | if ((zpi->type == IPSET_NET_NET) || |
1169 | (zpi->type == IPSET_NET_PORT_NET)) { | |
586f4ccf PG |
1170 | char buf[PREFIX_STRLEN]; |
1171 | ||
1172 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
1173 | vty_out(vty, "\tfrom %s", buf); | |
be729dd7 PG |
1174 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
1175 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
1176 | zebra_pbr_display_port(vty, zpie->filter_bm, |
1177 | zpie->src_port_min, | |
1178 | zpie->src_port_max, | |
1179 | zpie->proto); | |
586f4ccf PG |
1180 | vty_out(vty, " to "); |
1181 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
1182 | vty_out(vty, "%s", buf); | |
be729dd7 PG |
1183 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
1184 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
1185 | zebra_pbr_display_port(vty, zpie->filter_bm, |
1186 | zpie->dst_port_min, | |
1187 | zpie->dst_port_max, | |
1188 | zpie->proto); | |
be729dd7 PG |
1189 | if (zpie->proto == IPPROTO_ICMP) |
1190 | zebra_pbr_display_icmp(vty, zpie); | |
25d760c5 PG |
1191 | } else if ((zpi->type == IPSET_NET) || |
1192 | (zpi->type == IPSET_NET_PORT)) { | |
586f4ccf PG |
1193 | char buf[PREFIX_STRLEN]; |
1194 | ||
1195 | if (zpie->filter_bm & PBR_FILTER_SRC_IP) { | |
1196 | zebra_pbr_prefix2str(&(zpie->src), buf, sizeof(buf)); | |
1197 | vty_out(vty, "\tfrom %s", buf); | |
1198 | } | |
be729dd7 PG |
1199 | if (zpie->filter_bm & PBR_FILTER_SRC_PORT && |
1200 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
1201 | zebra_pbr_display_port(vty, zpie->filter_bm, |
1202 | zpie->src_port_min, | |
1203 | zpie->src_port_max, | |
1204 | zpie->proto); | |
586f4ccf PG |
1205 | if (zpie->filter_bm & PBR_FILTER_DST_IP) { |
1206 | zebra_pbr_prefix2str(&(zpie->dst), buf, sizeof(buf)); | |
1207 | vty_out(vty, "\tto %s", buf); | |
1208 | } | |
be729dd7 PG |
1209 | if (zpie->filter_bm & PBR_FILTER_DST_PORT && |
1210 | zpie->proto != IPPROTO_ICMP) | |
25d760c5 PG |
1211 | zebra_pbr_display_port(vty, zpie->filter_bm, |
1212 | zpie->dst_port_min, | |
1213 | zpie->dst_port_max, | |
1214 | zpie->proto); | |
be729dd7 PG |
1215 | if (zpie->proto == IPPROTO_ICMP) |
1216 | zebra_pbr_display_icmp(vty, zpie); | |
586f4ccf PG |
1217 | } |
1218 | vty_out(vty, " (%u)\n", zpie->unique); | |
1219 | ||
1c6fca1f | 1220 | ret = hook_call(zebra_pbr_ipset_entry_get_stat, zpie, &pkts, |
62f20a52 | 1221 | &bytes); |
73a829f7 PG |
1222 | if (ret && pkts > 0) |
1223 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
1224 | pkts, bytes); | |
586f4ccf PG |
1225 | return HASHWALK_CONTINUE; |
1226 | } | |
1227 | ||
e3b78da8 | 1228 | static int zebra_pbr_show_ipset_walkcb(struct hash_bucket *bucket, void *arg) |
586f4ccf PG |
1229 | { |
1230 | struct zebra_pbr_env_display *uniqueipset = | |
1231 | (struct zebra_pbr_env_display *)arg; | |
e3b78da8 | 1232 | struct zebra_pbr_ipset *zpi = (struct zebra_pbr_ipset *)bucket->data; |
586f4ccf PG |
1233 | struct zebra_pbr_ipset_entry_unique_display unique; |
1234 | struct vty *vty = uniqueipset->vty; | |
1235 | struct zebra_ns *zns = uniqueipset->zns; | |
1236 | ||
a60b7031 PG |
1237 | vty_out(vty, "IPset %s type %s family %s\n", zpi->ipset_name, |
1238 | zebra_pbr_ipset_type2str(zpi->type), | |
c6423c31 | 1239 | family2str(zpi->family)); |
586f4ccf PG |
1240 | unique.vty = vty; |
1241 | unique.zpi = zpi; | |
73a829f7 | 1242 | unique.zns = zns; |
62f20a52 | 1243 | hash_walk(zrouter.ipset_entry_hash, zebra_pbr_show_ipset_entry_walkcb, |
586f4ccf PG |
1244 | &unique); |
1245 | vty_out(vty, "\n"); | |
1246 | return HASHWALK_CONTINUE; | |
1247 | } | |
1248 | ||
dc993e76 PG |
1249 | size_t zebra_pbr_tcpflags_snprintf(char *buffer, size_t len, |
1250 | uint16_t tcp_val) | |
1251 | { | |
1252 | size_t len_written = 0; | |
1253 | static struct message nt = {0}; | |
1254 | const struct message *pnt; | |
1255 | int incr = 0; | |
1256 | ||
1257 | for (pnt = tcp_value_str; | |
1258 | memcmp(pnt, &nt, sizeof(struct message)); pnt++) | |
1259 | if (pnt->key & tcp_val) { | |
1260 | len_written += snprintf(buffer + len_written, | |
1261 | len - len_written, | |
1262 | "%s%s", incr ? | |
1263 | ",":"", pnt->str); | |
1264 | incr++; | |
1265 | } | |
1266 | return len_written; | |
1267 | } | |
1268 | ||
586f4ccf PG |
1269 | /* |
1270 | */ | |
1271 | void zebra_pbr_show_ipset_list(struct vty *vty, char *ipsetname) | |
1272 | { | |
1273 | struct zebra_pbr_ipset *zpi; | |
1274 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
1275 | struct zebra_pbr_ipset_entry_unique_display unique; | |
1276 | struct zebra_pbr_env_display uniqueipset; | |
1277 | ||
1278 | if (ipsetname) { | |
62f20a52 | 1279 | zpi = zebra_pbr_lookup_ipset_pername(ipsetname); |
586f4ccf PG |
1280 | if (!zpi) { |
1281 | vty_out(vty, "No IPset %s found\n", ipsetname); | |
1282 | return; | |
1283 | } | |
a60b7031 PG |
1284 | vty_out(vty, "IPset %s type %s family %s\n", ipsetname, |
1285 | zebra_pbr_ipset_type2str(zpi->type), | |
c6423c31 | 1286 | family2str(zpi->family)); |
586f4ccf PG |
1287 | unique.vty = vty; |
1288 | unique.zpi = zpi; | |
73a829f7 | 1289 | unique.zns = zns; |
62f20a52 DS |
1290 | hash_walk(zrouter.ipset_entry_hash, |
1291 | zebra_pbr_show_ipset_entry_walkcb, &unique); | |
586f4ccf PG |
1292 | return; |
1293 | } | |
1294 | uniqueipset.zns = zns; | |
1295 | uniqueipset.vty = vty; | |
7929821a | 1296 | uniqueipset.name = NULL; |
62f20a52 | 1297 | hash_walk(zrouter.ipset_hash, zebra_pbr_show_ipset_walkcb, |
586f4ccf PG |
1298 | &uniqueipset); |
1299 | } | |
1300 | ||
1301 | struct pbr_rule_fwmark_lookup { | |
1302 | struct zebra_pbr_rule *ptr; | |
1303 | uint32_t fwmark; | |
1304 | }; | |
1305 | ||
e3b78da8 | 1306 | static int zebra_pbr_rule_lookup_fwmark_walkcb(struct hash_bucket *bucket, |
586f4ccf PG |
1307 | void *arg) |
1308 | { | |
1309 | struct pbr_rule_fwmark_lookup *iprule = | |
1310 | (struct pbr_rule_fwmark_lookup *)arg; | |
e3b78da8 | 1311 | struct zebra_pbr_rule *zpr = (struct zebra_pbr_rule *)bucket->data; |
586f4ccf PG |
1312 | |
1313 | if (iprule->fwmark == zpr->rule.filter.fwmark) { | |
1314 | iprule->ptr = zpr; | |
1315 | return HASHWALK_ABORT; | |
1316 | } | |
1317 | return HASHWALK_CONTINUE; | |
1318 | } | |
1319 | ||
7929821a PG |
1320 | static void zebra_pbr_show_iptable_unit(struct zebra_pbr_iptable *iptable, |
1321 | struct vty *vty, | |
1322 | struct zebra_ns *zns) | |
586f4ccf | 1323 | { |
73a829f7 PG |
1324 | int ret; |
1325 | uint64_t pkts = 0, bytes = 0; | |
586f4ccf | 1326 | |
a60b7031 PG |
1327 | vty_out(vty, "IPtable %s family %s action %s (%u)\n", |
1328 | iptable->ipset_name, | |
c9b1139a | 1329 | family2str(iptable->family), |
586f4ccf PG |
1330 | iptable->action == ZEBRA_IPTABLES_DROP ? "drop" : "redirect", |
1331 | iptable->unique); | |
0b328d3f PG |
1332 | if (iptable->type == IPSET_NET_PORT || |
1333 | iptable->type == IPSET_NET_PORT_NET) { | |
1334 | if (!(iptable->filter_bm & MATCH_ICMP_SET)) { | |
1335 | if (iptable->filter_bm & PBR_FILTER_DST_PORT) | |
1336 | vty_out(vty, "\t lookup dst port\n"); | |
1337 | else if (iptable->filter_bm & PBR_FILTER_SRC_PORT) | |
1338 | vty_out(vty, "\t lookup src port\n"); | |
1339 | } | |
1340 | } | |
e7f7dad4 PG |
1341 | if (iptable->pkt_len_min || iptable->pkt_len_max) { |
1342 | if (!iptable->pkt_len_max) | |
1343 | vty_out(vty, "\t pkt len %u\n", | |
1344 | iptable->pkt_len_min); | |
1345 | else | |
1346 | vty_out(vty, "\t pkt len [%u;%u]\n", | |
1347 | iptable->pkt_len_min, | |
1348 | iptable->pkt_len_max); | |
1349 | } | |
dc993e76 PG |
1350 | if (iptable->tcp_flags || iptable->tcp_mask_flags) { |
1351 | char tcp_flag_str[64]; | |
1352 | char tcp_flag_mask_str[64]; | |
1353 | ||
1354 | zebra_pbr_tcpflags_snprintf(tcp_flag_str, | |
1355 | sizeof(tcp_flag_str), | |
1356 | iptable->tcp_flags); | |
1357 | zebra_pbr_tcpflags_snprintf(tcp_flag_mask_str, | |
1358 | sizeof(tcp_flag_mask_str), | |
1359 | iptable->tcp_mask_flags); | |
1360 | vty_out(vty, "\t tcpflags [%s/%s]\n", | |
1361 | tcp_flag_str, tcp_flag_mask_str); | |
1362 | } | |
69214c57 PG |
1363 | if (iptable->filter_bm & (MATCH_DSCP_SET | MATCH_DSCP_INVERSE_SET)) { |
1364 | vty_out(vty, "\t dscp %s %d\n", | |
1365 | iptable->filter_bm & MATCH_DSCP_INVERSE_SET ? | |
1366 | "not" : "", iptable->dscp_value); | |
1367 | } | |
a60b7031 PG |
1368 | if (iptable->filter_bm & (MATCH_FLOW_LABEL_SET | |
1369 | MATCH_FLOW_LABEL_INVERSE_SET)) { | |
1370 | vty_out(vty, "\t flowlabel %s %d\n", | |
1371 | iptable->filter_bm & MATCH_FLOW_LABEL_INVERSE_SET ? | |
1372 | "not" : "", iptable->flow_label); | |
1373 | } | |
5ac5b7cc PG |
1374 | if (iptable->fragment) { |
1375 | char val_str[10]; | |
1376 | ||
772270f3 | 1377 | snprintf(val_str, sizeof(val_str), "%d", iptable->fragment); |
5ac5b7cc PG |
1378 | vty_out(vty, "\t fragment%s %s\n", |
1379 | iptable->filter_bm & MATCH_FRAGMENT_INVERSE_SET ? | |
1380 | " not" : "", lookup_msg(fragment_value_str, | |
1381 | iptable->fragment, val_str)); | |
1382 | } | |
f449d223 PG |
1383 | if (iptable->protocol) { |
1384 | vty_out(vty, "\t protocol %d\n", | |
1385 | iptable->protocol); | |
1386 | } | |
1c6fca1f | 1387 | ret = hook_call(zebra_pbr_iptable_get_stat, iptable, &pkts, |
62f20a52 | 1388 | &bytes); |
73a829f7 PG |
1389 | if (ret && pkts > 0) |
1390 | vty_out(vty, "\t pkts %" PRIu64 ", bytes %" PRIu64"\n", | |
1391 | pkts, bytes); | |
586f4ccf PG |
1392 | if (iptable->action != ZEBRA_IPTABLES_DROP) { |
1393 | struct pbr_rule_fwmark_lookup prfl; | |
1394 | ||
1395 | prfl.fwmark = iptable->fwmark; | |
1396 | prfl.ptr = NULL; | |
7f0ea8a4 | 1397 | hash_walk(zrouter.rules_hash, |
586f4ccf PG |
1398 | &zebra_pbr_rule_lookup_fwmark_walkcb, &prfl); |
1399 | if (prfl.ptr) { | |
1400 | struct zebra_pbr_rule *zpr = prfl.ptr; | |
1401 | ||
1402 | vty_out(vty, "\t table %u, fwmark %u\n", | |
1403 | zpr->rule.action.table, | |
1404 | prfl.fwmark); | |
1405 | } | |
1406 | } | |
7929821a PG |
1407 | } |
1408 | ||
e3b78da8 | 1409 | static int zebra_pbr_show_iptable_walkcb(struct hash_bucket *bucket, void *arg) |
7929821a PG |
1410 | { |
1411 | struct zebra_pbr_iptable *iptable = | |
e3b78da8 | 1412 | (struct zebra_pbr_iptable *)bucket->data; |
7929821a PG |
1413 | struct zebra_pbr_env_display *env = (struct zebra_pbr_env_display *)arg; |
1414 | struct vty *vty = env->vty; | |
1415 | struct zebra_ns *zns = env->zns; | |
1416 | char *iptable_name = env->name; | |
1417 | ||
1418 | if (!iptable_name) | |
1419 | zebra_pbr_show_iptable_unit(iptable, vty, zns); | |
1420 | else if (!strncmp(iptable_name, | |
1421 | iptable->ipset_name, | |
1422 | ZEBRA_IPSET_NAME_SIZE)) | |
1423 | zebra_pbr_show_iptable_unit(iptable, vty, zns); | |
586f4ccf PG |
1424 | return HASHWALK_CONTINUE; |
1425 | } | |
1426 | ||
7929821a | 1427 | void zebra_pbr_show_iptable(struct vty *vty, char *iptable_name) |
586f4ccf PG |
1428 | { |
1429 | struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); | |
1430 | struct zebra_pbr_env_display env; | |
1431 | ||
1432 | env.vty = vty; | |
1433 | env.zns = zns; | |
7929821a | 1434 | env.name = iptable_name; |
62f20a52 | 1435 | hash_walk(zrouter.iptable_hash, zebra_pbr_show_iptable_walkcb, &env); |
586f4ccf | 1436 | } |
f80ec7e3 PG |
1437 | |
1438 | void zebra_pbr_iptable_update_interfacelist(struct stream *s, | |
1439 | struct zebra_pbr_iptable *zpi) | |
1440 | { | |
1441 | uint32_t i = 0, index; | |
1442 | struct interface *ifp; | |
1443 | char *name; | |
1444 | ||
1445 | for (i = 0; i < zpi->nb_interface; i++) { | |
1446 | STREAM_GETL(s, index); | |
1447 | ifp = if_lookup_by_index(index, zpi->vrf_id); | |
1448 | if (!ifp) | |
1449 | continue; | |
1450 | name = XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifp->name); | |
1451 | listnode_add(zpi->interface_name_list, name); | |
1452 | } | |
1453 | stream_failure: | |
1454 | return; | |
1455 | } |