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"
35 #include "pbr_zebra.h"
36 #include "pbr_memory.h"
37 #include "pbr_debug.h"
38 #include "pbr_vrf.h"
39 
40 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
41 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
42 DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
43 
44 static uint32_t pbr_map_sequence_unique;
45 
46 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm);
47 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
48 				  const struct pbr_map *pbrmap2);
49 
50 RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
51 
52 struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
53 
DEFINE_QOBJ_TYPE(pbr_map_sequence)54 DEFINE_QOBJ_TYPE(pbr_map_sequence)
55 
56 static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
57 				  const struct pbr_map *pbrmap2)
58 {
59 	return strcmp(pbrmap1->name, pbrmap2->name);
60 }
61 
pbr_map_sequence_compare(const struct pbr_map_sequence * pbrms1,const struct pbr_map_sequence * pbrms2)62 static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1,
63 				    const struct pbr_map_sequence *pbrms2)
64 {
65 	if (pbrms1->seqno == pbrms2->seqno)
66 		return 0;
67 
68 	if (pbrms1->seqno < pbrms2->seqno)
69 		return -1;
70 
71 	return 1;
72 }
73 
pbr_map_sequence_delete(struct pbr_map_sequence * pbrms)74 static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
75 {
76 	XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
77 
78 	QOBJ_UNREG(pbrms);
79 	XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
80 }
81 
pbr_map_interface_compare(const struct pbr_map_interface * pmi1,const struct pbr_map_interface * pmi2)82 static int pbr_map_interface_compare(const struct pbr_map_interface *pmi1,
83 				     const struct pbr_map_interface *pmi2)
84 {
85 	return strcmp(pmi1->ifp->name, pmi2->ifp->name);
86 }
87 
pbr_map_interface_list_delete(struct pbr_map_interface * pmi)88 static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
89 {
90 	struct pbr_map_interface *pmi_int;
91 	struct listnode *node, *nnode;
92 	struct pbr_map *pbrm;
93 
94 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
95 		for (ALL_LIST_ELEMENTS(pbrm->incoming, node, nnode, pmi_int)) {
96 			if (pmi == pmi_int) {
97 				pbr_map_policy_delete(pbrm, pmi);
98 				return;
99 			}
100 		}
101 	}
102 }
103 
pbrms_is_installed(const struct pbr_map_sequence * pbrms,const struct pbr_map_interface * pmi)104 static bool pbrms_is_installed(const struct pbr_map_sequence *pbrms,
105 			       const struct pbr_map_interface *pmi)
106 {
107 	uint64_t is_installed = (uint64_t)1 << pmi->install_bit;
108 
109 	is_installed &= pbrms->installed;
110 
111 	if (is_installed)
112 		return true;
113 
114 	return false;
115 }
116 
117 /* If any sequence is installed on the interface, assume installed */
118 static bool
pbr_map_interface_is_installed(const struct pbr_map * pbrm,const struct pbr_map_interface * check_pmi)119 pbr_map_interface_is_installed(const struct pbr_map *pbrm,
120 			       const struct pbr_map_interface *check_pmi)
121 {
122 
123 	struct pbr_map_sequence *pbrms;
124 	struct pbr_map_interface *pmi;
125 	struct listnode *node, *inode;
126 
127 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
128 		for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
129 			if (pmi == check_pmi && pbrms_is_installed(pbrms, pmi))
130 				return true;
131 
132 	return false;
133 }
134 
pbr_map_interface_is_valid(const struct pbr_map_interface * pmi)135 static bool pbr_map_interface_is_valid(const struct pbr_map_interface *pmi)
136 {
137 	/* Don't install rules without a real ifindex on the incoming interface.
138 	 *
139 	 * This can happen when we have config for an interface that does not
140 	 * exist or when an interface is changing vrfs.
141 	 */
142 	if (pmi->ifp && pmi->ifp->ifindex != IFINDEX_INTERNAL)
143 		return true;
144 
145 	return false;
146 }
147 
pbr_map_pbrms_update_common(struct pbr_map_sequence * pbrms,bool install,bool changed)148 static void pbr_map_pbrms_update_common(struct pbr_map_sequence *pbrms,
149 					bool install, bool changed)
150 {
151 	struct pbr_map *pbrm;
152 	struct listnode *node;
153 	struct pbr_map_interface *pmi;
154 
155 	pbrm = pbrms->parent;
156 
157 	if (pbrms->nhs_installed && pbrm->incoming->count) {
158 		for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
159 			if (!pmi->ifp)
160 				continue;
161 
162 			if (install && !pbr_map_interface_is_valid(pmi))
163 				continue;
164 
165 			pbr_send_pbr_map(pbrms, pmi, install, changed);
166 		}
167 	}
168 }
169 
pbr_map_pbrms_install(struct pbr_map_sequence * pbrms,bool changed)170 static void pbr_map_pbrms_install(struct pbr_map_sequence *pbrms, bool changed)
171 {
172 	pbr_map_pbrms_update_common(pbrms, true, changed);
173 }
174 
pbr_map_pbrms_uninstall(struct pbr_map_sequence * pbrms)175 static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms)
176 {
177 	pbr_map_pbrms_update_common(pbrms, false, false);
178 }
179 
180 static const char *const pbr_map_reason_str[] = {
181 	"Invalid NH-group",     "Invalid NH",	 "No Nexthops",
182 	"Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
183 	"Deleting Sequence",
184 };
185 
pbr_map_reason_string(unsigned int reason,char * buf,int size)186 void pbr_map_reason_string(unsigned int reason, char *buf, int size)
187 {
188 	unsigned int bit;
189 	int len = 0;
190 
191 	if (!buf)
192 		return;
193 
194 	for (bit = 0; bit < array_size(pbr_map_reason_str); bit++) {
195 		if ((reason & (1 << bit)) && (len < size)) {
196 			len += snprintf((buf + len), (size - len), "%s%s",
197 					(len > 0) ? ", " : "",
198 					pbr_map_reason_str[bit]);
199 		}
200 	}
201 }
202 
pbr_map_final_interface_deletion(struct pbr_map * pbrm,struct pbr_map_interface * pmi)203 void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
204 				      struct pbr_map_interface *pmi)
205 {
206 	if (pmi->delete && !pbr_map_interface_is_installed(pbrm, pmi)) {
207 		listnode_delete(pbrm->incoming, pmi);
208 		pmi->pbrm = NULL;
209 
210 		bf_release_index(pbrm->ifi_bitfield, pmi->install_bit);
211 		XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
212 	}
213 }
214 
pbr_map_interface_delete(struct pbr_map * pbrm,struct interface * ifp_del)215 void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del)
216 {
217 
218 	struct listnode *node;
219 	struct pbr_map_interface *pmi;
220 
221 	for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
222 		if (ifp_del == pmi->ifp)
223 			break;
224 	}
225 
226 	if (pmi)
227 		pbr_map_policy_delete(pbrm, pmi);
228 }
229 
pbr_map_add_interface(struct pbr_map * pbrm,struct interface * ifp_add)230 void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
231 {
232 	struct listnode *node;
233 	struct pbr_map_interface *pmi;
234 
235 	for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
236 		if (ifp_add == pmi->ifp)
237 			return;
238 	}
239 
240 	pmi = XCALLOC(MTYPE_PBR_MAP_INTERFACE, sizeof(*pmi));
241 	pmi->ifp = ifp_add;
242 	pmi->pbrm = pbrm;
243 	listnode_add_sort(pbrm->incoming, pmi);
244 
245 	bf_assign_index(pbrm->ifi_bitfield, pmi->install_bit);
246 	pbr_map_check_valid(pbrm->name);
247 	if (pbrm->valid)
248 		pbr_map_install(pbrm);
249 }
250 
251 static int
pbr_map_policy_interface_update_common(const struct interface * ifp,struct pbr_interface ** pbr_ifp,struct pbr_map ** pbrm)252 pbr_map_policy_interface_update_common(const struct interface *ifp,
253 				       struct pbr_interface **pbr_ifp,
254 				       struct pbr_map **pbrm)
255 {
256 	if (!ifp->info) {
257 		DEBUGD(&pbr_dbg_map, "%s: %s has no pbr_interface info",
258 		       __func__, ifp->name);
259 		return -1;
260 	}
261 
262 	*pbr_ifp = ifp->info;
263 
264 	*pbrm = pbrm_find((*pbr_ifp)->mapname);
265 
266 	if (!*pbrm) {
267 		DEBUGD(&pbr_dbg_map, "%s: applied PBR-MAP(%s) does not exist?",
268 		       __func__, (*pbr_ifp)->mapname);
269 		return -1;
270 	}
271 
272 	return 0;
273 }
274 
pbr_map_policy_interface_update(const struct interface * ifp,bool state_up)275 void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up)
276 {
277 	struct pbr_interface *pbr_ifp;
278 	struct pbr_map_sequence *pbrms;
279 	struct pbr_map *pbrm;
280 	struct listnode *node, *inode;
281 	struct pbr_map_interface *pmi;
282 
283 	if (pbr_map_policy_interface_update_common(ifp, &pbr_ifp, &pbrm))
284 		return;
285 
286 	DEBUGD(&pbr_dbg_map, "%s: %s %s rules on interface %s", __func__,
287 	       pbr_ifp->mapname, (state_up ? "installing" : "removing"),
288 	       ifp->name);
289 
290 	/*
291 	 * Walk the list and install/remove maps on the interface.
292 	 */
293 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
294 		for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
295 			if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi))
296 				pbr_send_pbr_map(pbrms, pmi, state_up, true);
297 }
298 
pbrms_vrf_update(struct pbr_map_sequence * pbrms,const struct pbr_vrf * pbr_vrf)299 static void pbrms_vrf_update(struct pbr_map_sequence *pbrms,
300 			     const struct pbr_vrf *pbr_vrf)
301 {
302 	const char *vrf_name = pbr_vrf_name(pbr_vrf);
303 
304 	if (pbrms->vrf_lookup
305 	    && (strncmp(vrf_name, pbrms->vrf_name, sizeof(pbrms->vrf_name))
306 		== 0)) {
307 		DEBUGD(&pbr_dbg_map, "\tSeq %u uses vrf %s (%u), updating map",
308 		       pbrms->seqno, vrf_name, pbr_vrf_id(pbr_vrf));
309 
310 		pbr_map_check(pbrms, false);
311 	}
312 }
313 
314 /* Vrf enabled/disabled */
pbr_map_vrf_update(const struct pbr_vrf * pbr_vrf)315 void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf)
316 {
317 	struct pbr_map *pbrm;
318 	struct pbr_map_sequence *pbrms;
319 	struct listnode *node;
320 
321 	if (!pbr_vrf)
322 		return;
323 
324 	bool enabled = pbr_vrf_is_enabled(pbr_vrf);
325 
326 	DEBUGD(&pbr_dbg_map, "%s: %s (%u) %s, updating pbr maps", __func__,
327 	       pbr_vrf_name(pbr_vrf), pbr_vrf_id(pbr_vrf),
328 	       enabled ? "enabled" : "disabled");
329 
330 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
331 		DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __func__, pbrm->name);
332 		for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
333 			pbrms_vrf_update(pbrms, pbr_vrf);
334 	}
335 }
336 
pbr_map_write_interfaces(struct vty * vty,struct interface * ifp)337 void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
338 {
339 	struct pbr_interface *pbr_ifp = ifp->info;
340 
341 	if (pbr_ifp
342 	    && strncmp(pbr_ifp->mapname, "", sizeof(pbr_ifp->mapname)) != 0)
343 		vty_out(vty, " pbr-policy %s\n", pbr_ifp->mapname);
344 }
345 
pbrm_find(const char * name)346 struct pbr_map *pbrm_find(const char *name)
347 {
348 	struct pbr_map pbrm;
349 
350 	strlcpy(pbrm.name, name, sizeof(pbrm.name));
351 
352 	return RB_FIND(pbr_map_entry_head, &pbr_maps, &pbrm);
353 }
354 
pbr_map_delete(struct pbr_map_sequence * pbrms)355 extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
356 {
357 	struct pbr_map *pbrm;
358 	struct listnode *inode;
359 	struct pbr_map_interface *pmi;
360 
361 	pbrm = pbrms->parent;
362 
363 	for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
364 		pbr_send_pbr_map(pbrms, pmi, false, false);
365 
366 	if (pbrms->nhg)
367 		pbr_nht_delete_individual_nexthop(pbrms);
368 
369 	listnode_delete(pbrm->seqnumbers, pbrms);
370 
371 	if (pbrm->seqnumbers->count == 0) {
372 		RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
373 
374 		bf_free(pbrm->ifi_bitfield);
375 		XFREE(MTYPE_PBR_MAP, pbrm);
376 	}
377 }
378 
pbr_map_delete_common(struct pbr_map_sequence * pbrms)379 static void pbr_map_delete_common(struct pbr_map_sequence *pbrms)
380 {
381 	struct pbr_map *pbrm = pbrms->parent;
382 
383 	pbr_map_pbrms_uninstall(pbrms);
384 
385 	pbrm->valid = false;
386 	pbrms->nhs_installed = false;
387 	pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
388 	XFREE(MTYPE_TMP, pbrms->nhgrp_name);
389 }
390 
pbr_map_delete_nexthops(struct pbr_map_sequence * pbrms)391 void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms)
392 {
393 	pbr_map_delete_common(pbrms);
394 }
395 
pbr_map_delete_vrf(struct pbr_map_sequence * pbrms)396 void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms)
397 {
398 	pbr_map_delete_common(pbrms);
399 }
400 
pbrms_lookup_unique(uint32_t unique,char * ifname,struct pbr_map_interface ** ppmi)401 struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, char *ifname,
402 					     struct pbr_map_interface **ppmi)
403 {
404 	struct pbr_map_sequence *pbrms;
405 	struct listnode *snode, *inode;
406 	struct pbr_map_interface *pmi;
407 	struct pbr_map *pbrm;
408 
409 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
410 		for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
411 			if (strncmp(pmi->ifp->name, ifname, INTERFACE_NAMSIZ)
412 			    != 0)
413 				continue;
414 
415 			if (ppmi)
416 				*ppmi = pmi;
417 
418 			for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
419 						  pbrms)) {
420 				DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
421 				       __func__, pbrms->unique, unique);
422 				if (pbrms->unique == unique)
423 					return pbrms;
424 			}
425 		}
426 	}
427 
428 	return NULL;
429 }
430 
pbr_map_add_interfaces(struct pbr_map * pbrm)431 static void pbr_map_add_interfaces(struct pbr_map *pbrm)
432 {
433 	struct interface *ifp;
434 	struct pbr_interface *pbr_ifp;
435 	struct vrf *vrf;
436 
437 	RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
438 		FOR_ALL_INTERFACES (vrf, ifp) {
439 			if (ifp->info) {
440 				pbr_ifp = ifp->info;
441 				if (strcmp(pbrm->name, pbr_ifp->mapname) == 0)
442 					pbr_map_add_interface(pbrm, ifp);
443 			}
444 		}
445 	}
446 }
447 
448 /* Decodes a standardized DSCP into its representative value */
pbr_map_decode_dscp_enum(const char * name)449 uint8_t pbr_map_decode_dscp_enum(const char *name)
450 {
451 	/* Standard Differentiated Services Field Codepoints */
452 	if (!strcmp(name, "cs0"))
453 		return 0;
454 	if (!strcmp(name, "cs1"))
455 		return 8;
456 	if (!strcmp(name, "cs2"))
457 		return 16;
458 	if (!strcmp(name, "cs3"))
459 		return 24;
460 	if (!strcmp(name, "cs4"))
461 		return 32;
462 	if (!strcmp(name, "cs5"))
463 		return 40;
464 	if (!strcmp(name, "cs6"))
465 		return 48;
466 	if (!strcmp(name, "cs7"))
467 		return 56;
468 	if (!strcmp(name, "af11"))
469 		return 10;
470 	if (!strcmp(name, "af12"))
471 		return 12;
472 	if (!strcmp(name, "af13"))
473 		return 14;
474 	if (!strcmp(name, "af21"))
475 		return 18;
476 	if (!strcmp(name, "af22"))
477 		return 20;
478 	if (!strcmp(name, "af23"))
479 		return 22;
480 	if (!strcmp(name, "af31"))
481 		return 26;
482 	if (!strcmp(name, "af32"))
483 		return 28;
484 	if (!strcmp(name, "af33"))
485 		return 30;
486 	if (!strcmp(name, "af41"))
487 		return 34;
488 	if (!strcmp(name, "af42"))
489 		return 36;
490 	if (!strcmp(name, "af43"))
491 		return 38;
492 	if (!strcmp(name, "ef"))
493 		return 46;
494 	if (!strcmp(name, "voice-admit"))
495 		return 44;
496 
497 	/* No match? Error out */
498 	return -1;
499 }
500 
pbrms_get(const char * name,uint32_t seqno)501 struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
502 {
503 	struct pbr_map *pbrm;
504 	struct pbr_map_sequence *pbrms;
505 	struct listnode *node;
506 
507 	pbrm = pbrm_find(name);
508 	if (!pbrm) {
509 		pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
510 		snprintf(pbrm->name, sizeof(pbrm->name), "%s", name);
511 
512 		pbrm->seqnumbers = list_new();
513 		pbrm->seqnumbers->cmp =
514 			(int (*)(void *, void *))pbr_map_sequence_compare;
515 		pbrm->seqnumbers->del =
516 			 (void (*)(void *))pbr_map_sequence_delete;
517 
518 		pbrm->incoming = list_new();
519 		pbrm->incoming->cmp =
520 			(int (*)(void *, void *))pbr_map_interface_compare;
521 		pbrm->incoming->del =
522 			(void (*)(void *))pbr_map_interface_list_delete;
523 
524 		RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
525 
526 		bf_init(pbrm->ifi_bitfield, 64);
527 		pbr_map_add_interfaces(pbrm);
528 	}
529 
530 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
531 		if (pbrms->seqno == seqno)
532 			break;
533 
534 	}
535 
536 	if (!pbrms) {
537 		pbrms = XCALLOC(MTYPE_PBR_MAP_SEQNO, sizeof(*pbrms));
538 		pbrms->unique = pbr_map_sequence_unique++;
539 		pbrms->seqno = seqno;
540 		pbrms->ruleno = pbr_nht_get_next_rule(seqno);
541 		pbrms->parent = pbrm;
542 		pbrms->reason =
543 			PBR_MAP_INVALID_EMPTY |
544 			PBR_MAP_INVALID_NO_NEXTHOPS;
545 		pbrms->vrf_name[0] = '\0';
546 
547 		QOBJ_REG(pbrms, pbr_map_sequence);
548 		listnode_add_sort(pbrm->seqnumbers, pbrms);
549 	}
550 
551 	return pbrms;
552 }
553 
554 static void
pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence * pbrms)555 pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
556 {
557 	/* Check if any are present first */
558 	if (!pbrms->vrf_unchanged && !pbrms->vrf_lookup && !pbrms->nhg
559 	    && !pbrms->nhgrp_name) {
560 		pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
561 		return;
562 	}
563 
564 	/*
565 	 * Check validness of vrf.
566 	 */
567 
568 	/* This one can be considered always valid */
569 	if (pbrms->vrf_unchanged)
570 		pbrms->nhs_installed = true;
571 
572 	if (pbrms->vrf_lookup) {
573 		struct pbr_vrf *pbr_vrf =
574 			pbr_vrf_lookup_by_name(pbrms->vrf_name);
575 
576 		if (pbr_vrf && pbr_vrf_is_valid(pbr_vrf))
577 			pbrms->nhs_installed = true;
578 		else
579 			pbrms->reason |= PBR_MAP_INVALID_VRF;
580 	}
581 
582 	/*
583 	 * Check validness of the nexthop or nexthop-group
584 	 */
585 
586 	/* Only nexthop or nexthop group allowed */
587 	if (pbrms->nhg && pbrms->nhgrp_name)
588 		pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
589 
590 	if (pbrms->nhg &&
591 	    !pbr_nht_nexthop_group_valid(pbrms->internal_nhg_name))
592 		pbrms->reason |= PBR_MAP_INVALID_NEXTHOP;
593 
594 	if (pbrms->nhgrp_name) {
595 		if (!pbr_nht_nexthop_group_valid(pbrms->nhgrp_name))
596 			pbrms->reason |= PBR_MAP_INVALID_NEXTHOP_GROUP;
597 		else
598 			pbrms->nhs_installed = true;
599 	}
600 }
601 
pbr_map_sequence_check_not_empty(struct pbr_map_sequence * pbrms)602 static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
603 {
604 	if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield)
605 		pbrms->reason |= PBR_MAP_INVALID_EMPTY;
606 }
607 
608 /*
609  * Checks to see if we think that the pbmrs is valid.  If we think
610  * the config is valid return true.
611  */
pbr_map_sequence_check_valid(struct pbr_map_sequence * pbrms)612 static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
613 {
614 	pbr_map_sequence_check_nexthops_valid(pbrms);
615 
616 	pbr_map_sequence_check_not_empty(pbrms);
617 }
618 
pbr_map_check_valid_internal(struct pbr_map * pbrm)619 static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
620 {
621 	struct pbr_map_sequence *pbrms;
622 	struct listnode *node;
623 
624 	pbrm->valid = true;
625 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
626 		pbrms->reason = 0;
627 		pbr_map_sequence_check_valid(pbrms);
628 		/*
629 		 * A pbr_map_sequence that is invalid causes
630 		 * the whole shebang to be invalid
631 		 */
632 		if (pbrms->reason != 0)
633 			pbrm->valid = false;
634 	}
635 
636 	return pbrm->valid;
637 }
638 
639 /*
640  * For a given PBR-MAP check to see if we think it is a
641  * valid config or not.  If so note that it is and return
642  * that we are valid.
643  */
pbr_map_check_valid(const char * name)644 bool pbr_map_check_valid(const char *name)
645 {
646 	struct pbr_map *pbrm;
647 
648 	pbrm = pbrm_find(name);
649 	if (!pbrm) {
650 		DEBUGD(&pbr_dbg_map,
651 		       "%s: Specified PBR-MAP(%s) does not exist?", __func__,
652 		       name);
653 		return false;
654 	}
655 
656 	pbr_map_check_valid_internal(pbrm);
657 	return pbrm->valid;
658 }
659 
pbr_map_schedule_policy_from_nhg(const char * nh_group,bool installed)660 void pbr_map_schedule_policy_from_nhg(const char *nh_group, bool installed)
661 {
662 	struct pbr_map_sequence *pbrms;
663 	struct pbr_map *pbrm;
664 	struct listnode *node;
665 
666 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
667 		DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __func__, pbrm->name);
668 		for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
669 			DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
670 			       pbrms->nhgrp_name ?
671 			       pbrms->nhgrp_name : pbrms->internal_nhg_name);
672 
673 			if (pbrms->nhgrp_name
674 			    && (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
675 				pbrms->nhs_installed = installed;
676 
677 				pbr_map_check(pbrms, false);
678 			}
679 
680 			if (pbrms->nhg
681 			    && (strcmp(nh_group, pbrms->internal_nhg_name)
682 				== 0)) {
683 				pbrms->nhs_installed = installed;
684 
685 				pbr_map_check(pbrms, false);
686 			}
687 		}
688 	}
689 }
690 
pbr_map_policy_install(const char * name)691 void pbr_map_policy_install(const char *name)
692 {
693 	struct pbr_map_sequence *pbrms;
694 	struct pbr_map *pbrm;
695 	struct listnode *node, *inode;
696 	struct pbr_map_interface *pmi;
697 
698 	DEBUGD(&pbr_dbg_map, "%s: for %s", __func__, name);
699 	pbrm = pbrm_find(name);
700 	if (!pbrm)
701 		return;
702 
703 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
704 		DEBUGD(&pbr_dbg_map,
705 		       "%s: Looking at what to install %s(%u) %d %d", __func__,
706 		       name, pbrms->seqno, pbrm->valid, pbrms->nhs_installed);
707 
708 		if (pbrm->valid && pbrms->nhs_installed
709 		    && pbrm->incoming->count) {
710 			DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", pbrm->name,
711 			       pbrms->seqno);
712 			for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
713 				if (pbr_map_interface_is_valid(pmi))
714 					pbr_send_pbr_map(pbrms, pmi, true,
715 							 false);
716 		}
717 	}
718 }
719 
pbr_map_policy_delete(struct pbr_map * pbrm,struct pbr_map_interface * pmi)720 void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
721 {
722 	struct listnode *node;
723 	struct pbr_map_sequence *pbrms;
724 	bool sent = false;
725 
726 
727 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
728 		if (pbr_send_pbr_map(pbrms, pmi, false, true))
729 			sent = true; /* rule removal sent to zebra */
730 
731 	pmi->delete = true;
732 
733 	/*
734 	 * If we actually sent something for deletion, wait on zapi callback
735 	 * before clearing data.
736 	 */
737 	if (sent)
738 		return;
739 
740 	pbr_map_final_interface_deletion(pbrm, pmi);
741 }
742 
743 /*
744  * For a nexthop group specified, see if any of the pbr-maps
745  * are using it and if so, check to see that we are still
746  * valid for usage.  If we are valid then schedule the installation/deletion
747  * of the pbr-policy.
748  */
pbr_map_check_nh_group_change(const char * nh_group)749 void pbr_map_check_nh_group_change(const char *nh_group)
750 {
751 	struct pbr_map_sequence *pbrms;
752 	struct pbr_map *pbrm;
753 	struct listnode *node, *inode;
754 	struct pbr_map_interface *pmi;
755 	bool found_name;
756 
757 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
758 		for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
759 			found_name = false;
760 			if (pbrms->nhgrp_name)
761 				found_name =
762 					!strcmp(nh_group, pbrms->nhgrp_name);
763 			else if (pbrms->nhg)
764 				found_name = !strcmp(nh_group,
765 						     pbrms->internal_nhg_name);
766 
767 			if (found_name) {
768 				bool original = pbrm->valid;
769 
770 				pbr_map_check_valid_internal(pbrm);
771 
772 				if (pbrm->valid && (original != pbrm->valid))
773 					pbr_map_install(pbrm);
774 
775 				if (pbrm->valid == false)
776 					for (ALL_LIST_ELEMENTS_RO(
777 						     pbrm->incoming, inode,
778 						     pmi))
779 						pbr_send_pbr_map(pbrms, pmi,
780 								 false, false);
781 			}
782 		}
783 	}
784 }
785 
pbr_map_check_vrf_nh_group_change(const char * nh_group,struct pbr_vrf * pbr_vrf,uint32_t old_vrf_id)786 void pbr_map_check_vrf_nh_group_change(const char *nh_group,
787 				       struct pbr_vrf *pbr_vrf,
788 				       uint32_t old_vrf_id)
789 {
790 	struct pbr_map *pbrm;
791 	struct pbr_map_sequence *pbrms;
792 	struct listnode *node;
793 
794 
795 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
796 		for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
797 			if (pbrms->nhgrp_name)
798 				continue;
799 
800 			if (pbrms->nhg == NULL)
801 				continue;
802 
803 			if (strcmp(nh_group, pbrms->internal_nhg_name))
804 				continue;
805 
806 			if (pbrms->nhg->nexthop == NULL)
807 				continue;
808 
809 			if (pbrms->nhg->nexthop->vrf_id != old_vrf_id)
810 				continue;
811 
812 			pbrms->nhg->nexthop->vrf_id = pbr_vrf_id(pbr_vrf);
813 		}
814 	}
815 }
816 
pbr_map_check_interface_nh_group_change(const char * nh_group,struct interface * ifp,ifindex_t oldifindex)817 void pbr_map_check_interface_nh_group_change(const char *nh_group,
818 					     struct interface *ifp,
819 					     ifindex_t oldifindex)
820 {
821 	struct pbr_map *pbrm;
822 	struct pbr_map_sequence *pbrms;
823 	struct listnode *node;
824 
825 	RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
826 		for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
827 			if (pbrms->nhgrp_name)
828 				continue;
829 
830 			if (pbrms->nhg == NULL)
831 				continue;
832 
833 			if (strcmp(nh_group, pbrms->internal_nhg_name))
834 				continue;
835 
836 			if (pbrms->nhg->nexthop == NULL)
837 				continue;
838 
839 			if (pbrms->nhg->nexthop->ifindex != oldifindex)
840 				continue;
841 
842 			pbrms->nhg->nexthop->ifindex = ifp->ifindex;
843 		}
844 	}
845 }
846 
pbr_map_check(struct pbr_map_sequence * pbrms,bool changed)847 void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed)
848 {
849 	struct pbr_map *pbrm;
850 	bool install;
851 
852 	pbrm = pbrms->parent;
853 	DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __func__, pbrm->name,
854 	       pbrms->seqno);
855 	if (pbr_map_check_valid(pbrm->name))
856 		DEBUGD(&pbr_dbg_map, "We are totally valid %s",
857 		       pbrm->name);
858 
859 	if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
860 		install = true;
861 		DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
862 		       __func__, pbrm->name, pbrms->seqno, pbrms->reason);
863 		DEBUGD(&pbr_dbg_map,
864 		       "\tSending PBR_MAP_POLICY_INSTALL event");
865 	} else {
866 		install = false;
867 		DEBUGD(&pbr_dbg_map, "%s: Removing %s(%u) reason: %" PRIu64,
868 		       __func__, pbrm->name, pbrms->seqno, pbrms->reason);
869 	}
870 
871 	if (install)
872 		pbr_map_pbrms_install(pbrms, changed);
873 	else
874 		pbr_map_pbrms_uninstall(pbrms);
875 }
876 
pbr_map_install(struct pbr_map * pbrm)877 void pbr_map_install(struct pbr_map *pbrm)
878 {
879 	struct pbr_map_sequence *pbrms;
880 	struct listnode *node;
881 
882 	if (!pbrm->incoming->count)
883 		return;
884 
885 	for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
886 		pbr_map_pbrms_install(pbrms, false);
887 }
888 
pbr_map_init(void)889 void pbr_map_init(void)
890 {
891 	RB_INIT(pbr_map_entry_head, &pbr_maps);
892 
893 	pbr_map_sequence_unique = 1;
894 }
895