]>
Commit | Line | Data |
---|---|---|
e5c83d9b DS |
1 | /* |
2 | * PBR-map Code | |
3 | * Copyright (C) 2018 Cumulus Networks, Inc. | |
4 | * Donald Sharp | |
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 along | |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | #include <zebra.h> | |
21 | ||
22 | #include "thread.h" | |
23 | #include "linklist.h" | |
24 | #include "prefix.h" | |
25 | #include "table.h" | |
26 | #include "vrf.h" | |
27 | #include "nexthop.h" | |
28 | #include "nexthop_group.h" | |
29 | #include "memory.h" | |
30 | #include "log.h" | |
31 | #include "vty.h" | |
32 | ||
33 | #include "pbr_nht.h" | |
34 | #include "pbr_map.h" | |
e5c83d9b DS |
35 | #include "pbr_zebra.h" |
36 | #include "pbr_memory.h" | |
37 | #include "pbr_debug.h" | |
38 | ||
39 | DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map") | |
40 | DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence") | |
41 | DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface") | |
42 | ||
43 | static uint32_t pbr_map_sequence_unique; | |
44 | ||
d3765386 DS |
45 | static inline int pbr_map_compare(const struct pbr_map *pbrmap1, |
46 | const struct pbr_map *pbrmap2); | |
e5c83d9b DS |
47 | |
48 | RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare) | |
49 | ||
50 | struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps); | |
51 | ||
52 | DEFINE_QOBJ_TYPE(pbr_map_sequence) | |
53 | ||
d3765386 DS |
54 | static inline int pbr_map_compare(const struct pbr_map *pbrmap1, |
55 | const struct pbr_map *pbrmap2) | |
e5c83d9b DS |
56 | { |
57 | return strcmp(pbrmap1->name, pbrmap2->name); | |
58 | } | |
59 | ||
60 | static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1, | |
61 | const struct pbr_map_sequence *pbrms2) | |
62 | { | |
63 | if (pbrms1->seqno == pbrms2->seqno) | |
64 | return 0; | |
65 | ||
66 | if (pbrms1->seqno < pbrms2->seqno) | |
67 | return -1; | |
68 | ||
69 | return 1; | |
70 | } | |
71 | ||
72 | static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms) | |
73 | { | |
74 | if (pbrms->internal_nhg_name) | |
75 | XFREE(MTYPE_TMP, pbrms->internal_nhg_name); | |
76 | ||
77 | XFREE(MTYPE_PBR_MAP_SEQNO, pbrms); | |
78 | } | |
79 | ||
80 | static int pbr_map_interface_compare(const struct pbr_map_interface *pmi1, | |
81 | const struct pbr_map_interface *pmi2) | |
82 | { | |
83 | return strcmp(pmi1->ifp->name, pmi2->ifp->name); | |
84 | } | |
85 | ||
b13e5ad6 | 86 | static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi) |
e5c83d9b | 87 | { |
b13e5ad6 DS |
88 | struct pbr_map_interface *pmi_int; |
89 | struct listnode *node, *nnode; | |
90 | struct pbr_map *pbrm; | |
91 | ||
92 | RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { | |
93 | for (ALL_LIST_ELEMENTS(pbrm->incoming, node, nnode, pmi_int)) { | |
94 | if (pmi == pmi_int) { | |
95 | pbr_map_policy_delete(pbrm, pmi); | |
96 | return; | |
97 | } | |
98 | } | |
99 | } | |
e5c83d9b DS |
100 | } |
101 | ||
102 | static const char *pbr_map_reason_str[] = { | |
103 | "Invalid NH-group", "Invalid NH", "No Nexthops", | |
104 | "Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence", | |
105 | }; | |
106 | ||
107 | void pbr_map_reason_string(unsigned int reason, char *buf, int size) | |
108 | { | |
109 | unsigned int bit; | |
110 | int len = 0; | |
111 | ||
112 | if (!buf) | |
113 | return; | |
114 | ||
115 | for (bit = 0; bit < array_size(pbr_map_reason_str); bit++) { | |
116 | if ((reason & (1 << bit)) && (len < size)) { | |
117 | len += snprintf((buf + len), (size - len), "%s%s", | |
118 | (len > 0) ? ", " : "", | |
119 | pbr_map_reason_str[bit]); | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | ||
125 | void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del) | |
126 | { | |
127 | ||
128 | struct listnode *node; | |
129 | struct pbr_map_interface *pmi; | |
e5c83d9b DS |
130 | |
131 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) { | |
132 | if (ifp_del == pmi->ifp) | |
133 | break; | |
134 | } | |
135 | ||
b13e5ad6 DS |
136 | if (pmi) |
137 | pbr_map_policy_delete(pbrm, pmi); | |
e5c83d9b DS |
138 | } |
139 | ||
140 | void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add) | |
141 | { | |
142 | struct listnode *node; | |
143 | struct pbr_map_interface *pmi; | |
e5c83d9b DS |
144 | |
145 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) { | |
146 | if (ifp_add == pmi->ifp) | |
147 | return; | |
148 | } | |
149 | ||
150 | pmi = XCALLOC(MTYPE_PBR_MAP_INTERFACE, sizeof(*pmi)); | |
151 | pmi->ifp = ifp_add; | |
152 | pmi->pbrm = pbrm; | |
153 | listnode_add_sort(pbrm->incoming, pmi); | |
154 | ||
37c606ff | 155 | bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit); |
b13e5ad6 | 156 | pbr_map_check_valid(pbrm->name); |
d02e9432 | 157 | if (pbrm->valid) |
b13e5ad6 | 158 | pbr_map_install(pbrm); |
e5c83d9b DS |
159 | } |
160 | ||
161 | void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp) | |
162 | { | |
163 | struct pbr_interface *pbr_ifp = ifp->info; | |
164 | ||
f1c3fe1b QY |
165 | if (pbr_ifp |
166 | && strncmp(pbr_ifp->mapname, "", sizeof(pbr_ifp->mapname)) != 0) | |
e5c83d9b DS |
167 | vty_out(vty, " pbr-policy %s\n", pbr_ifp->mapname); |
168 | } | |
169 | ||
170 | struct pbr_map *pbrm_find(const char *name) | |
171 | { | |
172 | struct pbr_map pbrm; | |
173 | ||
174 | strlcpy(pbrm.name, name, sizeof(pbrm.name)); | |
175 | ||
176 | return RB_FIND(pbr_map_entry_head, &pbr_maps, &pbrm); | |
177 | } | |
178 | ||
b13e5ad6 | 179 | extern void pbr_map_delete(struct pbr_map_sequence *pbrms) |
e5c83d9b DS |
180 | { |
181 | struct pbr_map *pbrm; | |
b13e5ad6 DS |
182 | struct listnode *inode; |
183 | struct pbr_map_interface *pmi; | |
e5c83d9b | 184 | |
b13e5ad6 | 185 | pbrm = pbrms->parent; |
e5c83d9b | 186 | |
b13e5ad6 DS |
187 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) |
188 | pbr_send_pbr_map(pbrms, pmi, false); | |
e5c83d9b | 189 | |
b13e5ad6 DS |
190 | if (pbrms->nhg) |
191 | pbr_nht_delete_individual_nexthop(pbrms); | |
e5c83d9b | 192 | |
b13e5ad6 | 193 | listnode_delete(pbrm->seqnumbers, pbrms); |
e5c83d9b DS |
194 | |
195 | if (pbrm->seqnumbers->count == 0) { | |
196 | RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm); | |
37c606ff DS |
197 | |
198 | bf_free(pbrm->ifi_bitfield); | |
e5c83d9b DS |
199 | XFREE(MTYPE_PBR_MAP, pbrm); |
200 | } | |
201 | } | |
202 | ||
b13e5ad6 DS |
203 | void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms) |
204 | { | |
205 | struct pbr_map *pbrm = pbrms->parent; | |
206 | struct listnode *node; | |
207 | struct pbr_map_interface *pmi; | |
208 | ||
209 | if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { | |
210 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) | |
211 | pbr_send_pbr_map(pbrms, pmi, false); | |
212 | } | |
213 | ||
214 | pbrm->valid = false; | |
215 | pbrms->nhs_installed = false; | |
b13e5ad6 DS |
216 | pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; |
217 | pbrms->nhgrp_name = NULL; | |
218 | } | |
219 | ||
37c606ff DS |
220 | struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex, |
221 | struct pbr_map_interface **ppmi) | |
e5c83d9b DS |
222 | { |
223 | struct pbr_map_sequence *pbrms; | |
224 | struct listnode *snode, *inode; | |
225 | struct pbr_map_interface *pmi; | |
226 | struct pbr_map *pbrm; | |
227 | ||
228 | RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { | |
229 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) { | |
230 | if (pmi->ifp->ifindex != ifindex) | |
231 | continue; | |
232 | ||
37c606ff DS |
233 | if (ppmi) |
234 | *ppmi = pmi; | |
235 | ||
e5c83d9b DS |
236 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, |
237 | pbrms)) { | |
238 | DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u", | |
239 | __PRETTY_FUNCTION__, pbrms->unique, | |
240 | unique); | |
241 | if (pbrms->unique == unique) | |
242 | return pbrms; | |
243 | } | |
244 | } | |
245 | } | |
246 | ||
247 | return NULL; | |
248 | } | |
249 | ||
b13e5ad6 DS |
250 | static void pbr_map_add_interfaces(struct pbr_map *pbrm) |
251 | { | |
252 | struct interface *ifp; | |
253 | struct pbr_interface *pbr_ifp; | |
254 | struct vrf *vrf; | |
255 | ||
256 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
257 | FOR_ALL_INTERFACES (vrf, ifp) { | |
258 | if (ifp->info) { | |
259 | pbr_ifp = ifp->info; | |
260 | if (strcmp(pbrm->name, pbr_ifp->mapname) == 0) | |
261 | pbr_map_add_interface(pbrm, ifp); | |
262 | } | |
263 | } | |
264 | } | |
265 | } | |
266 | ||
d3765386 | 267 | struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) |
e5c83d9b DS |
268 | { |
269 | struct pbr_map *pbrm; | |
270 | struct pbr_map_sequence *pbrms; | |
271 | struct listnode *node; | |
e5c83d9b DS |
272 | |
273 | pbrm = pbrm_find(name); | |
274 | if (!pbrm) { | |
275 | pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm)); | |
6612590d | 276 | snprintf(pbrm->name, sizeof(pbrm->name), "%s", name); |
e5c83d9b DS |
277 | |
278 | pbrm->seqnumbers = list_new(); | |
279 | pbrm->seqnumbers->cmp = | |
280 | (int (*)(void *, void *))pbr_map_sequence_compare; | |
281 | pbrm->seqnumbers->del = | |
282 | (void (*)(void *))pbr_map_sequence_delete; | |
283 | ||
284 | pbrm->incoming = list_new(); | |
285 | pbrm->incoming->cmp = | |
286 | (int (*)(void *, void *))pbr_map_interface_compare; | |
287 | pbrm->incoming->del = | |
288 | (void (*)(void *))pbr_map_interface_list_delete; | |
289 | ||
290 | RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm); | |
291 | ||
37c606ff | 292 | bf_init(pbrm->ifi_bitfield, 64); |
b13e5ad6 DS |
293 | pbr_map_add_interfaces(pbrm); |
294 | } | |
e5c83d9b DS |
295 | |
296 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { | |
297 | if (pbrms->seqno == seqno) | |
298 | break; | |
299 | ||
300 | } | |
301 | ||
302 | if (!pbrms) { | |
303 | pbrms = XCALLOC(MTYPE_PBR_MAP_SEQNO, sizeof(*pbrms)); | |
304 | pbrms->unique = pbr_map_sequence_unique++; | |
305 | pbrms->seqno = seqno; | |
306 | pbrms->ruleno = pbr_nht_get_next_rule(seqno); | |
307 | pbrms->parent = pbrm; | |
308 | pbrms->reason = | |
309 | PBR_MAP_INVALID_SRCDST | | |
310 | PBR_MAP_INVALID_NO_NEXTHOPS; | |
311 | ||
312 | QOBJ_REG(pbrms, pbr_map_sequence); | |
313 | listnode_add_sort(pbrm->seqnumbers, pbrms); | |
e5c83d9b DS |
314 | } |
315 | ||
e5c83d9b DS |
316 | return pbrms; |
317 | } | |
318 | ||
319 | static void | |
320 | pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms) | |
321 | { | |
322 | /* | |
323 | * Check validness of the nexthop or nexthop-group | |
324 | */ | |
325 | if (!pbrms->nhg && !pbrms->nhgrp_name) | |
326 | pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS; | |
327 | ||
328 | if (pbrms->nhg && pbrms->nhgrp_name) | |
329 | pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP; | |
330 | ||
331 | if (pbrms->nhg && | |
332 | !pbr_nht_nexthop_group_valid(pbrms->internal_nhg_name)) | |
333 | pbrms->reason |= PBR_MAP_INVALID_NEXTHOP; | |
334 | ||
335 | if (pbrms->nhgrp_name) { | |
336 | if (!pbr_nht_nexthop_group_valid(pbrms->nhgrp_name)) | |
337 | pbrms->reason |= PBR_MAP_INVALID_NEXTHOP_GROUP; | |
338 | else | |
339 | pbrms->nhs_installed = true; | |
340 | } | |
341 | } | |
342 | ||
343 | static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence *pbrms) | |
344 | { | |
345 | if (!pbrms->src && !pbrms->dst) | |
346 | pbrms->reason |= PBR_MAP_INVALID_SRCDST; | |
347 | } | |
348 | ||
349 | /* | |
350 | * Checks to see if we think that the pbmrs is valid. If we think | |
351 | * the config is valid return true. | |
352 | */ | |
353 | static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms) | |
354 | { | |
355 | pbr_map_sequence_check_nexthops_valid(pbrms); | |
356 | ||
357 | pbr_map_sequence_check_src_dst_valid(pbrms); | |
358 | } | |
359 | ||
360 | static bool pbr_map_check_valid_internal(struct pbr_map *pbrm) | |
361 | { | |
362 | struct pbr_map_sequence *pbrms; | |
363 | struct listnode *node; | |
364 | ||
365 | pbrm->valid = true; | |
366 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { | |
367 | pbrms->reason = 0; | |
368 | pbr_map_sequence_check_valid(pbrms); | |
369 | /* | |
370 | * A pbr_map_sequence that is invalid causes | |
371 | * the whole shebang to be invalid | |
372 | */ | |
373 | if (pbrms->reason != 0) | |
374 | pbrm->valid = false; | |
375 | } | |
376 | ||
377 | return pbrm->valid; | |
378 | } | |
379 | ||
380 | /* | |
381 | * For a given PBR-MAP check to see if we think it is a | |
382 | * valid config or not. If so note that it is and return | |
383 | * that we are valid. | |
384 | */ | |
d3765386 | 385 | bool pbr_map_check_valid(const char *name) |
e5c83d9b DS |
386 | { |
387 | struct pbr_map *pbrm; | |
388 | ||
389 | pbrm = pbrm_find(name); | |
390 | if (!pbrm) { | |
391 | DEBUGD(&pbr_dbg_map, | |
392 | "%s: Specified PBR-MAP(%s) does not exist?", | |
393 | __PRETTY_FUNCTION__, name); | |
394 | return false; | |
395 | } | |
396 | ||
397 | pbr_map_check_valid_internal(pbrm); | |
398 | return pbrm->valid; | |
399 | } | |
400 | ||
d3765386 | 401 | void pbr_map_schedule_policy_from_nhg(const char *nh_group) |
e5c83d9b DS |
402 | { |
403 | struct pbr_map_sequence *pbrms; | |
e5c83d9b DS |
404 | struct pbr_map *pbrm; |
405 | struct listnode *node; | |
406 | ||
407 | RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { | |
408 | DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __PRETTY_FUNCTION__, | |
409 | pbrm->name); | |
410 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { | |
411 | DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s", | |
2f61710b DS |
412 | pbrms->nhgrp_name ? |
413 | pbrms->nhgrp_name : pbrms->internal_nhg_name); | |
e5c83d9b DS |
414 | |
415 | if (pbrms->nhgrp_name | |
416 | && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) { | |
417 | pbrms->nhs_installed = true; | |
418 | ||
b13e5ad6 | 419 | pbr_map_check(pbrms); |
e5c83d9b DS |
420 | } |
421 | ||
422 | if (pbrms->nhg | |
423 | && (strcmp(nh_group, pbrms->internal_nhg_name) | |
424 | == 0)) { | |
425 | pbrms->nhs_installed = true; | |
426 | ||
b13e5ad6 | 427 | pbr_map_check(pbrms); |
e5c83d9b DS |
428 | } |
429 | } | |
430 | } | |
431 | } | |
432 | ||
d3765386 | 433 | void pbr_map_policy_install(const char *name) |
e5c83d9b DS |
434 | { |
435 | struct pbr_map_sequence *pbrms; | |
436 | struct pbr_map *pbrm; | |
b13e5ad6 DS |
437 | struct listnode *node, *inode; |
438 | struct pbr_map_interface *pmi; | |
e5c83d9b DS |
439 | |
440 | DEBUGD(&pbr_dbg_map, "%s: for %s", __PRETTY_FUNCTION__, name); | |
441 | pbrm = pbrm_find(name); | |
442 | if (!pbrm) | |
443 | return; | |
444 | ||
e5c83d9b DS |
445 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { |
446 | DEBUGD(&pbr_dbg_map, | |
447 | "%s: Looking at what to install %s(%u) %d %d", | |
448 | __PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid, | |
449 | pbrms->nhs_installed); | |
e5c83d9b | 450 | |
b13e5ad6 DS |
451 | if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { |
452 | DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", | |
453 | pbrm->name, pbrms->seqno); | |
454 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) | |
455 | pbr_send_pbr_map(pbrms, pmi, true); | |
456 | } | |
e5c83d9b DS |
457 | } |
458 | } | |
459 | ||
b13e5ad6 | 460 | void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi) |
e5c83d9b | 461 | { |
b13e5ad6 DS |
462 | struct listnode *node; |
463 | struct pbr_map_sequence *pbrms; | |
e5c83d9b | 464 | |
e5c83d9b | 465 | |
b13e5ad6 DS |
466 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) |
467 | pbr_send_pbr_map(pbrms, pmi, false); | |
468 | ||
469 | listnode_delete(pbrm->incoming, pmi); | |
470 | pmi->pbrm = NULL; | |
37c606ff DS |
471 | |
472 | bf_release_index(pbrm->ifi_bitfield, pmi->install_bit); | |
b13e5ad6 | 473 | XFREE(MTYPE_PBR_MAP_INTERFACE, pmi); |
e5c83d9b DS |
474 | } |
475 | ||
476 | /* | |
477 | * For a nexthop group specified, see if any of the pbr-maps | |
478 | * are using it and if so, check to see that we are still | |
479 | * valid for usage. If we are valid then schedule the installation/deletion | |
480 | * of the pbr-policy. | |
481 | */ | |
d3765386 | 482 | void pbr_map_check_nh_group_change(const char *nh_group) |
e5c83d9b DS |
483 | { |
484 | struct pbr_map_sequence *pbrms; | |
485 | struct pbr_map *pbrm; | |
ff9799c3 DS |
486 | struct listnode *node, *inode; |
487 | struct pbr_map_interface *pmi; | |
e5c83d9b DS |
488 | bool found_name; |
489 | ||
e5c83d9b DS |
490 | RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { |
491 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) { | |
492 | found_name = false; | |
493 | if (pbrms->nhgrp_name) | |
494 | found_name = | |
495 | !strcmp(nh_group, pbrms->nhgrp_name); | |
496 | else if (pbrms->nhg) | |
497 | found_name = !strcmp(nh_group, | |
498 | pbrms->internal_nhg_name); | |
499 | ||
500 | if (found_name) { | |
501 | bool original = pbrm->valid; | |
e5c83d9b DS |
502 | |
503 | pbr_map_check_valid_internal(pbrm); | |
504 | ||
ff9799c3 | 505 | if (pbrm->valid && (original != pbrm->valid)) |
b13e5ad6 | 506 | pbr_map_install(pbrm); |
ff9799c3 DS |
507 | |
508 | if (pbrm->valid == false) | |
509 | for (ALL_LIST_ELEMENTS_RO( | |
510 | pbrm->incoming, inode, | |
511 | pmi)) | |
512 | pbr_send_pbr_map(pbrms, pmi, | |
513 | false); | |
e5c83d9b DS |
514 | } |
515 | } | |
516 | } | |
517 | } | |
518 | ||
b13e5ad6 | 519 | void pbr_map_check(struct pbr_map_sequence *pbrms) |
e5c83d9b | 520 | { |
e5c83d9b | 521 | struct pbr_map *pbrm; |
b13e5ad6 DS |
522 | struct listnode *inode; |
523 | struct pbr_map_interface *pmi; | |
524 | bool install; | |
e5c83d9b | 525 | |
b13e5ad6 DS |
526 | pbrm = pbrms->parent; |
527 | DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__, | |
528 | pbrm->name, pbrms->seqno); | |
529 | if (pbr_map_check_valid(pbrm->name)) | |
2f61710b | 530 | DEBUGD(&pbr_dbg_map, "We are totally valid %s", |
b13e5ad6 | 531 | pbrm->name); |
e5c83d9b | 532 | |
b13e5ad6 DS |
533 | if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) { |
534 | install = true; | |
e5c83d9b | 535 | DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64, |
b13e5ad6 DS |
536 | __PRETTY_FUNCTION__, pbrm->name, pbrms->seqno, |
537 | pbrms->reason); | |
e5c83d9b | 538 | DEBUGD(&pbr_dbg_map, |
b13e5ad6 DS |
539 | "\tSending PBR_MAP_POLICY_INSTALL event"); |
540 | } else { | |
541 | install = false; | |
e5c83d9b | 542 | DEBUGD(&pbr_dbg_map, |
b13e5ad6 DS |
543 | "%s: Removing %s(%u) reason: %" PRIu64, |
544 | __PRETTY_FUNCTION__, pbrm->name, | |
545 | pbrms->seqno, pbrms->reason); | |
e5c83d9b DS |
546 | } |
547 | ||
2fb7892e | 548 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) { |
b13e5ad6 | 549 | pbr_send_pbr_map(pbrms, pmi, install); |
2fb7892e | 550 | } |
e5c83d9b DS |
551 | } |
552 | ||
b13e5ad6 | 553 | void pbr_map_install(struct pbr_map *pbrm) |
e5c83d9b | 554 | { |
b13e5ad6 DS |
555 | struct listnode *node, *inode; |
556 | struct pbr_map_sequence *pbrms; | |
557 | struct pbr_map_interface *pmi; | |
e5c83d9b | 558 | |
b13e5ad6 | 559 | if (!pbrm->incoming->count) |
e5c83d9b | 560 | return; |
e5c83d9b | 561 | |
b13e5ad6 DS |
562 | for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) |
563 | for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) | |
564 | pbr_send_pbr_map(pbrms, pmi, true); | |
e5c83d9b DS |
565 | } |
566 | ||
d3765386 | 567 | void pbr_map_init(void) |
e5c83d9b DS |
568 | { |
569 | RB_INIT(pbr_map_entry_head, &pbr_maps); | |
570 | ||
571 | pbr_map_sequence_unique = 1; | |
572 | } |