]>
Commit | Line | Data |
---|---|---|
5921ef9a PJ |
1 | /* zebra routemap. |
2 | * Copyright (C) 2006 IBM Corporation | |
3 | * | |
4 | * This file is part of GNU Zebra. | |
5 | * | |
6 | * GNU Zebra 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 | * GNU Zebra 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 | * | |
896014f4 DL |
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 | |
5921ef9a PJ |
19 | */ |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "memory.h" | |
24 | #include "prefix.h" | |
25 | #include "rib.h" | |
82f97584 | 26 | #include "vty.h" |
5921ef9a PJ |
27 | #include "routemap.h" |
28 | #include "command.h" | |
29 | #include "filter.h" | |
30 | #include "plist.h" | |
fb018d25 | 31 | #include "nexthop.h" |
07d030ea | 32 | #include "northbound_cli.h" |
09781197 | 33 | #include "lib/route_types.h" |
0032dd59 | 34 | #include "vrf.h" |
5d5ba018 | 35 | #include "frrstr.h" |
5921ef9a | 36 | |
3801e764 | 37 | #include "zebra/zebra_router.h" |
8902474b | 38 | #include "zebra/redistribute.h" |
518f0eb1 | 39 | #include "zebra/debug.h" |
9f0ea7d4 | 40 | #include "zebra/zebra_rnh.h" |
6baf7bb8 | 41 | #include "zebra/zebra_routemap.h" |
518f0eb1 | 42 | |
214e5c26 | 43 | #include "zebra/zebra_routemap_clippy.c" |
214e5c26 | 44 | |
d7c0a89a | 45 | static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER; |
518f0eb1 | 46 | static struct thread *zebra_t_rmap_update = NULL; |
8902474b | 47 | char *zebra_import_table_routemap[AFI_MAX][ZEBRA_KERNEL_TABLE_MAX]; |
518f0eb1 | 48 | |
d62a17ae | 49 | struct nh_rmap_obj { |
50 | struct nexthop *nexthop; | |
51 | vrf_id_t vrf_id; | |
d7c0a89a | 52 | uint32_t source_protocol; |
633a66a5 | 53 | uint8_t instance; |
d62a17ae | 54 | int metric; |
55 | route_tag_t tag; | |
9f0ea7d4 DS |
56 | }; |
57 | ||
d7c0a89a | 58 | static void zebra_route_map_set_delay_timer(uint32_t value); |
5921ef9a | 59 | |
ca84c8ef DS |
60 | /* 'match tag TAG' |
61 | * Match function return 1 if match is success else return 0 | |
62 | */ | |
b68885f9 | 63 | static enum route_map_cmd_result_t |
1782514f | 64 | route_match_tag(void *rule, const struct prefix *prefix, void *object) |
ca84c8ef | 65 | { |
d62a17ae | 66 | route_tag_t *tag; |
67 | struct nh_rmap_obj *nh_data; | |
ca84c8ef | 68 | |
1782514f DS |
69 | tag = rule; |
70 | nh_data = object; | |
71 | ||
72 | if (nh_data->tag == *tag) | |
73 | return RMAP_MATCH; | |
ca84c8ef | 74 | |
d62a17ae | 75 | return RMAP_NOMATCH; |
ca84c8ef DS |
76 | } |
77 | ||
ca84c8ef | 78 | /* Route map commands for tag matching */ |
364deb04 DL |
79 | static const struct route_map_rule_cmd route_match_tag_cmd = { |
80 | "tag", | |
81 | route_match_tag, | |
82 | route_map_rule_tag_compile, | |
d62a17ae | 83 | route_map_rule_tag_free, |
ca84c8ef DS |
84 | }; |
85 | ||
6b0655a2 | 86 | |
5921ef9a PJ |
87 | /* `match interface IFNAME' */ |
88 | /* Match function return 1 if match is success else return zero. */ | |
b68885f9 | 89 | static enum route_map_cmd_result_t |
1782514f | 90 | route_match_interface(void *rule, const struct prefix *prefix, void *object) |
d62a17ae | 91 | { |
92 | struct nh_rmap_obj *nh_data; | |
93 | char *ifname = rule; | |
94 | ifindex_t ifindex; | |
95 | ||
1782514f DS |
96 | if (strcasecmp(ifname, "any") == 0) |
97 | return RMAP_MATCH; | |
98 | nh_data = object; | |
99 | if (!nh_data || !nh_data->nexthop) | |
100 | return RMAP_NOMATCH; | |
101 | ifindex = ifname2ifindex(ifname, nh_data->vrf_id); | |
102 | if (ifindex == 0) | |
103 | return RMAP_NOMATCH; | |
104 | if (nh_data->nexthop->ifindex == ifindex) | |
105 | return RMAP_MATCH; | |
106 | ||
0032dd59 | 107 | return RMAP_NOMATCH; |
5921ef9a PJ |
108 | } |
109 | ||
110 | /* Route map `match interface' match statement. `arg' is IFNAME value */ | |
d62a17ae | 111 | static void *route_match_interface_compile(const char *arg) |
5921ef9a | 112 | { |
d62a17ae | 113 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); |
5921ef9a PJ |
114 | } |
115 | ||
116 | /* Free route map's compiled `match interface' value. */ | |
d62a17ae | 117 | static void route_match_interface_free(void *rule) |
5921ef9a | 118 | { |
d62a17ae | 119 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
120 | } |
121 | ||
7cf16e19 | 122 | static void show_vrf_proto_rm(struct vty *vty, struct zebra_vrf *zvrf, |
123 | int af_type) | |
124 | { | |
125 | int i; | |
126 | ||
59f81419 DS |
127 | vty_out(vty, "Protocol : route-map\n"); |
128 | vty_out(vty, "-------------------------------------\n"); | |
7cf16e19 | 129 | |
130 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
131 | if (PROTO_RM_NAME(zvrf, af_type, i)) | |
59f81419 | 132 | vty_out(vty, "%-24s : %-10s\n", zebra_route_string(i), |
7cf16e19 | 133 | PROTO_RM_NAME(zvrf, af_type, i)); |
134 | else | |
59f81419 | 135 | vty_out(vty, "%-24s : none\n", zebra_route_string(i)); |
7cf16e19 | 136 | } |
137 | ||
138 | if (PROTO_RM_NAME(zvrf, af_type, i)) | |
59f81419 | 139 | vty_out(vty, "%-24s : %-10s\n", "any", |
7cf16e19 | 140 | PROTO_RM_NAME(zvrf, af_type, i)); |
141 | else | |
59f81419 | 142 | vty_out(vty, "%-24s : none\n", "any"); |
7cf16e19 | 143 | } |
144 | ||
145 | static void show_vrf_nht_rm(struct vty *vty, struct zebra_vrf *zvrf, | |
63e7deba | 146 | int af_type, json_object *json) |
7cf16e19 | 147 | { |
148 | int i; | |
149 | ||
63e7deba SPG |
150 | if (!json) { |
151 | vty_out(vty, "Protocol : route-map\n"); | |
152 | vty_out(vty, "-------------------------------------\n"); | |
153 | } | |
7cf16e19 | 154 | |
155 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { | |
63e7deba SPG |
156 | if (json) { |
157 | if (NHT_RM_NAME(zvrf, af_type, i)) | |
158 | json_object_string_add( | |
159 | json, zebra_route_string(i), | |
160 | NHT_RM_NAME(zvrf, af_type, i)); | |
161 | else | |
162 | json_object_string_add( | |
163 | json, zebra_route_string(i), "none"); | |
164 | } else { | |
165 | if (NHT_RM_NAME(zvrf, af_type, i)) | |
166 | vty_out(vty, "%-24s : %-10s\n", | |
167 | zebra_route_string(i), | |
168 | NHT_RM_NAME(zvrf, af_type, i)); | |
169 | else | |
170 | vty_out(vty, "%-24s : none\n", | |
171 | zebra_route_string(i)); | |
172 | } | |
173 | } | |
174 | ||
175 | if (json) { | |
7cf16e19 | 176 | if (NHT_RM_NAME(zvrf, af_type, i)) |
63e7deba SPG |
177 | json_object_string_add(json, "any", |
178 | NHT_RM_NAME(zvrf, af_type, i)); | |
179 | else | |
180 | json_object_string_add(json, "any", "none"); | |
181 | } else { | |
182 | if (NHT_RM_NAME(zvrf, af_type, i)) | |
183 | vty_out(vty, "%-24s : %-10s\n", "any", | |
7cf16e19 | 184 | NHT_RM_NAME(zvrf, af_type, i)); |
185 | else | |
63e7deba | 186 | vty_out(vty, "%-24s : none\n", "any"); |
7cf16e19 | 187 | } |
7cf16e19 | 188 | } |
189 | ||
190 | static int show_proto_rm(struct vty *vty, int af_type, const char *vrf_all, | |
191 | const char *vrf_name) | |
192 | { | |
193 | struct zebra_vrf *zvrf; | |
194 | ||
195 | if (vrf_all) { | |
196 | struct vrf *vrf; | |
197 | ||
198 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { | |
199 | zvrf = (struct zebra_vrf *)vrf->info; | |
200 | if (zvrf == NULL) | |
201 | continue; | |
202 | vty_out(vty, "VRF: %s\n", zvrf->vrf->name); | |
203 | show_vrf_proto_rm(vty, zvrf, af_type); | |
204 | } | |
205 | } else { | |
206 | vrf_id_t vrf_id = VRF_DEFAULT; | |
207 | ||
208 | if (vrf_name) | |
209 | VRF_GET_ID(vrf_id, vrf_name, false); | |
210 | ||
211 | zvrf = zebra_vrf_lookup_by_id(vrf_id); | |
212 | if (!zvrf) | |
213 | return CMD_SUCCESS; | |
214 | ||
215 | vty_out(vty, "VRF: %s\n", zvrf->vrf->name); | |
216 | show_vrf_proto_rm(vty, zvrf, af_type); | |
217 | } | |
218 | ||
219 | return CMD_SUCCESS; | |
220 | } | |
221 | ||
222 | static int show_nht_rm(struct vty *vty, int af_type, const char *vrf_all, | |
63e7deba | 223 | const char *vrf_name, bool use_json) |
7cf16e19 | 224 | { |
225 | struct zebra_vrf *zvrf; | |
63e7deba SPG |
226 | json_object *json = NULL; |
227 | json_object *json_vrfs = NULL; | |
228 | ||
229 | if (use_json) { | |
230 | json = json_object_new_object(); | |
231 | json_vrfs = json_object_new_object(); | |
232 | json_object_string_add(json, "afi", | |
233 | (af_type == AFI_IP) ? "ipv4" : "ipv6"); | |
234 | } | |
7cf16e19 | 235 | |
236 | if (vrf_all) { | |
237 | struct vrf *vrf; | |
238 | ||
63e7deba SPG |
239 | if (use_json) |
240 | json_object_object_add(json, "vrfs", json_vrfs); | |
241 | ||
7cf16e19 | 242 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
243 | zvrf = (struct zebra_vrf *)vrf->info; | |
244 | if (zvrf == NULL) | |
245 | continue; | |
246 | ||
63e7deba SPG |
247 | if (use_json) { |
248 | json_object *json_proto = NULL; | |
249 | json_object *json_vrf = NULL; | |
250 | json_vrf = json_object_new_object(); | |
251 | json_object_object_add( | |
252 | json_vrfs, zvrf->vrf->name, json_vrf); | |
253 | json_proto = json_object_new_object(); | |
254 | json_object_object_add(json_vrf, "protocols", | |
255 | json_proto); | |
256 | show_vrf_nht_rm(vty, zvrf, af_type, json_proto); | |
257 | } else { | |
258 | vty_out(vty, "VRF: %s\n", zvrf->vrf->name); | |
259 | show_vrf_nht_rm(vty, zvrf, af_type, NULL); | |
260 | } | |
7cf16e19 | 261 | } |
262 | } else { | |
63e7deba SPG |
263 | json_object *json_proto = NULL; |
264 | json_object *json_vrf = NULL; | |
7cf16e19 | 265 | vrf_id_t vrf_id = VRF_DEFAULT; |
266 | ||
267 | if (vrf_name) | |
268 | VRF_GET_ID(vrf_id, vrf_name, false); | |
269 | ||
270 | zvrf = zebra_vrf_lookup_by_id(vrf_id); | |
63e7deba SPG |
271 | if (!zvrf) { |
272 | json_object_free(json); | |
273 | json_object_free(json_vrfs); | |
7cf16e19 | 274 | return CMD_SUCCESS; |
63e7deba | 275 | } |
7cf16e19 | 276 | |
63e7deba SPG |
277 | if (use_json) { |
278 | json_object_object_add(json, "vrfs", json_vrfs); | |
279 | json_vrf = json_object_new_object(); | |
280 | json_object_object_add(json_vrfs, zvrf->vrf->name, | |
281 | json_vrf); | |
282 | json_proto = json_object_new_object(); | |
283 | json_object_object_add(json_vrf, "protocols", | |
284 | json_proto); | |
285 | show_vrf_nht_rm(vty, zvrf, af_type, json_proto); | |
286 | } else { | |
287 | vty_out(vty, "VRF: %s\n", zvrf->vrf->name); | |
288 | show_vrf_nht_rm(vty, zvrf, af_type, NULL); | |
289 | } | |
7cf16e19 | 290 | } |
291 | ||
63e7deba SPG |
292 | if (use_json) |
293 | vty_json(vty, json); | |
294 | ||
7cf16e19 | 295 | return CMD_SUCCESS; |
296 | } | |
297 | ||
5921ef9a | 298 | /* Route map commands for interface matching */ |
364deb04 DL |
299 | static const struct route_map_rule_cmd route_match_interface_cmd = { |
300 | "interface", | |
301 | route_match_interface, | |
302 | route_match_interface_compile, | |
303 | route_match_interface_free | |
304 | }; | |
5921ef9a | 305 | |
214e5c26 | 306 | static int ip_protocol_rm_add(struct zebra_vrf *zvrf, const char *rmap, |
307 | int rtype, afi_t afi, safi_t safi) | |
308 | { | |
309 | struct route_table *table; | |
310 | ||
311 | if (PROTO_RM_NAME(zvrf, afi, rtype)) { | |
312 | if (strcmp(PROTO_RM_NAME(zvrf, afi, rtype), rmap) == 0) | |
313 | return CMD_SUCCESS; | |
314 | ||
315 | XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype)); | |
316 | } | |
54e80c76 | 317 | route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); |
214e5c26 | 318 | PROTO_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); |
319 | PROTO_RM_MAP(zvrf, afi, rtype) = | |
320 | route_map_lookup_by_name(PROTO_RM_NAME(zvrf, afi, rtype)); | |
54e80c76 | 321 | route_map_counter_increment(PROTO_RM_MAP(zvrf, afi, rtype)); |
214e5c26 | 322 | |
323 | if (PROTO_RM_MAP(zvrf, afi, rtype)) { | |
324 | ||
325 | if (IS_ZEBRA_DEBUG_RIB_DETAILED) | |
326 | zlog_debug( | |
327 | "%u: IPv4 Routemap config for protocol %d scheduling RIB processing", | |
328 | zvrf->vrf->vrf_id, rtype); | |
329 | /* Process routes of interested address-families. */ | |
330 | table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id); | |
331 | if (table) | |
54aeba35 | 332 | rib_update_table(table, RIB_UPDATE_RMAP_CHANGE, |
cfcd844c | 333 | rtype); |
214e5c26 | 334 | } |
335 | ||
336 | return CMD_SUCCESS; | |
337 | } | |
338 | ||
339 | static int ip_protocol_rm_del(struct zebra_vrf *zvrf, const char *rmap, | |
340 | int rtype, afi_t afi, safi_t safi) | |
341 | { | |
342 | struct route_table *table; | |
343 | ||
344 | if (!PROTO_RM_NAME(zvrf, afi, rtype)) | |
345 | return CMD_SUCCESS; | |
346 | ||
347 | if (!rmap || strcmp(rmap, PROTO_RM_NAME(zvrf, afi, rtype)) == 0) { | |
54e80c76 | 348 | |
349 | route_map_counter_decrement(PROTO_RM_MAP(zvrf, afi, rtype)); | |
214e5c26 | 350 | if (PROTO_RM_MAP(zvrf, afi, rtype)) { |
351 | if (IS_ZEBRA_DEBUG_RIB_DETAILED) | |
352 | zlog_debug( | |
353 | "%u: IPv4 Routemap unconfig for protocol %d, scheduling RIB processing", | |
354 | zvrf->vrf->vrf_id, rtype); | |
355 | PROTO_RM_MAP(zvrf, afi, rtype) = NULL; | |
356 | ||
357 | /* Process routes of interested address-families. */ | |
358 | table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id); | |
359 | if (table) | |
54aeba35 | 360 | rib_update_table(table, RIB_UPDATE_RMAP_CHANGE, |
cfcd844c | 361 | rtype); |
214e5c26 | 362 | } |
363 | XFREE(MTYPE_ROUTE_MAP_NAME, PROTO_RM_NAME(zvrf, afi, rtype)); | |
364 | } | |
365 | return CMD_SUCCESS; | |
366 | } | |
367 | ||
368 | static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, | |
369 | int afi) | |
370 | { | |
371 | ||
372 | if (NHT_RM_NAME(zvrf, afi, rtype)) { | |
373 | if (strcmp(NHT_RM_NAME(zvrf, afi, rtype), rmap) == 0) | |
374 | return CMD_SUCCESS; | |
375 | ||
376 | XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); | |
377 | } | |
54e80c76 | 378 | route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); |
214e5c26 | 379 | NHT_RM_NAME(zvrf, afi, rtype) = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap); |
380 | NHT_RM_MAP(zvrf, afi, rtype) = | |
381 | route_map_lookup_by_name(NHT_RM_NAME(zvrf, afi, rtype)); | |
54e80c76 | 382 | route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype)); |
214e5c26 | 383 | |
384 | if (NHT_RM_MAP(zvrf, afi, rtype)) | |
d597533a | 385 | zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); |
214e5c26 | 386 | |
387 | return CMD_SUCCESS; | |
388 | } | |
389 | ||
390 | static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, | |
391 | int afi) | |
392 | { | |
393 | ||
394 | if (!NHT_RM_NAME(zvrf, afi, rtype)) | |
395 | return CMD_SUCCESS; | |
396 | ||
397 | if (!rmap || strcmp(rmap, NHT_RM_NAME(zvrf, afi, rtype)) == 0) { | |
54e80c76 | 398 | route_map_counter_decrement(NHT_RM_MAP(zvrf, afi, rtype)); |
214e5c26 | 399 | if (NHT_RM_MAP(zvrf, afi, rtype)) { |
400 | if (IS_ZEBRA_DEBUG_RIB_DETAILED) | |
401 | zlog_debug( | |
402 | "%u: IPv4 Routemap unconfig for protocol %d, scheduling RIB processing", | |
403 | zvrf->vrf->vrf_id, rtype); | |
404 | NHT_RM_MAP(zvrf, afi, rtype) = NULL; | |
405 | ||
d597533a | 406 | zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); |
214e5c26 | 407 | } |
408 | XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); | |
409 | } | |
410 | return CMD_SUCCESS; | |
411 | } | |
412 | ||
ca77b518 | 413 | DEFPY_YANG( |
07d030ea RZ |
414 | match_ip_address_prefix_len, match_ip_address_prefix_len_cmd, |
415 | "match ip address prefix-len (0-32)$length", | |
416 | MATCH_STR | |
417 | IP_STR | |
418 | "Match prefix length of IP address\n" | |
419 | "Match prefix length of IP address\n" | |
420 | "Prefix length\n") | |
9f0ea7d4 | 421 | { |
e71627cb SP |
422 | const char *xpath = |
423 | "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; | |
07d030ea RZ |
424 | char xpath_value[XPATH_MAXLEN]; |
425 | ||
426 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
e71627cb SP |
427 | snprintf( |
428 | xpath_value, sizeof(xpath_value), | |
429 | "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", | |
430 | xpath); | |
07d030ea RZ |
431 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); |
432 | ||
433 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
434 | } |
435 | ||
ca77b518 | 436 | DEFPY_YANG( |
07d030ea RZ |
437 | no_match_ip_address_prefix_len, no_match_ip_address_prefix_len_cmd, |
438 | "no match ip address prefix-len [(0-32)]", | |
439 | NO_STR | |
440 | MATCH_STR | |
441 | IP_STR | |
442 | "Match prefix length of IP address\n" | |
443 | "Match prefix length of IP address\n" | |
444 | "Prefix length\n") | |
9f0ea7d4 | 445 | { |
e71627cb SP |
446 | const char *xpath = |
447 | "./match-condition[condition='frr-zebra-route-map:ipv4-prefix-length']"; | |
07d030ea RZ |
448 | |
449 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
450 | ||
451 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
452 | } |
453 | ||
ca77b518 | 454 | DEFPY_YANG( |
07d030ea RZ |
455 | match_ipv6_address_prefix_len, match_ipv6_address_prefix_len_cmd, |
456 | "match ipv6 address prefix-len (0-128)$length", | |
457 | MATCH_STR | |
458 | IPV6_STR | |
459 | "Match prefix length of IPv6 address\n" | |
460 | "Match prefix length of IPv6 address\n" | |
461 | "Prefix length\n") | |
5165d46f | 462 | { |
e71627cb SP |
463 | const char *xpath = |
464 | "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; | |
07d030ea RZ |
465 | char xpath_value[XPATH_MAXLEN]; |
466 | ||
467 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
e71627cb SP |
468 | snprintf( |
469 | xpath_value, sizeof(xpath_value), | |
470 | "%s/rmap-match-condition/frr-zebra-route-map:ipv6-prefix-length", | |
471 | xpath); | |
07d030ea RZ |
472 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); |
473 | ||
474 | return nb_cli_apply_changes(vty, NULL); | |
5165d46f DS |
475 | } |
476 | ||
ca77b518 | 477 | DEFPY_YANG( |
07d030ea RZ |
478 | no_match_ipv6_address_prefix_len, no_match_ipv6_address_prefix_len_cmd, |
479 | "no match ipv6 address prefix-len [(0-128)]", | |
480 | NO_STR | |
481 | MATCH_STR | |
482 | IPV6_STR | |
483 | "Match prefix length of IPv6 address\n" | |
484 | "Match prefix length of IPv6 address\n" | |
485 | "Prefix length\n") | |
5165d46f | 486 | { |
e71627cb SP |
487 | const char *xpath = |
488 | "./match-condition[condition='frr-zebra-route-map:ipv6-prefix-length']"; | |
07d030ea RZ |
489 | |
490 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
491 | ||
492 | return nb_cli_apply_changes(vty, NULL); | |
5165d46f | 493 | } |
9f0ea7d4 | 494 | |
ca77b518 | 495 | DEFPY_YANG( |
07d030ea RZ |
496 | match_ip_nexthop_prefix_len, match_ip_nexthop_prefix_len_cmd, |
497 | "match ip next-hop prefix-len (0-32)$length", | |
498 | MATCH_STR | |
499 | IP_STR | |
500 | "Match prefixlen of nexthop IP address\n" | |
501 | "Match prefixlen of given nexthop\n" | |
502 | "Prefix length\n") | |
9f0ea7d4 | 503 | { |
07d030ea | 504 | const char *xpath = |
e71627cb | 505 | "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; |
07d030ea RZ |
506 | char xpath_value[XPATH_MAXLEN]; |
507 | ||
508 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
e71627cb SP |
509 | snprintf( |
510 | xpath_value, sizeof(xpath_value), | |
511 | "%s/rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length", | |
512 | xpath); | |
07d030ea RZ |
513 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, length_str); |
514 | ||
515 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
516 | } |
517 | ||
ca77b518 | 518 | DEFPY_YANG( |
07d030ea RZ |
519 | no_match_ip_nexthop_prefix_len, no_match_ip_nexthop_prefix_len_cmd, |
520 | "no match ip next-hop prefix-len [(0-32)]", | |
521 | NO_STR | |
522 | MATCH_STR | |
523 | IP_STR | |
524 | "Match prefixlen of nexthop IP address\n" | |
525 | "Match prefix length of nexthop\n" | |
526 | "Prefix length\n") | |
9f0ea7d4 | 527 | { |
07d030ea | 528 | const char *xpath = |
e71627cb | 529 | "./match-condition[condition='frr-zebra-route-map:ipv4-next-hop-prefix-length']"; |
07d030ea RZ |
530 | |
531 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
532 | ||
533 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
534 | } |
535 | ||
ca77b518 | 536 | DEFPY_YANG( |
07d030ea RZ |
537 | match_source_protocol, match_source_protocol_cmd, |
538 | "match source-protocol " FRR_REDIST_STR_ZEBRA "$proto", | |
539 | MATCH_STR | |
540 | "Match protocol via which the route was learnt\n" | |
541 | FRR_REDIST_HELP_STR_ZEBRA) | |
9f0ea7d4 | 542 | { |
e71627cb SP |
543 | const char *xpath = |
544 | "./match-condition[condition='frr-zebra-route-map:source-protocol']"; | |
07d030ea | 545 | char xpath_value[XPATH_MAXLEN]; |
9f0ea7d4 | 546 | |
07d030ea RZ |
547 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); |
548 | snprintf(xpath_value, sizeof(xpath_value), | |
e71627cb SP |
549 | "%s/rmap-match-condition/frr-zebra-route-map:source-protocol", |
550 | xpath); | |
07d030ea RZ |
551 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto); |
552 | ||
553 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
554 | } |
555 | ||
ca77b518 | 556 | DEFPY_YANG( |
07d030ea RZ |
557 | no_match_source_protocol, no_match_source_protocol_cmd, |
558 | "no match source-protocol [" FRR_REDIST_STR_ZEBRA "]", | |
559 | NO_STR | |
560 | MATCH_STR | |
561 | "Match protocol via which the route was learnt\n" | |
562 | FRR_REDIST_HELP_STR_ZEBRA) | |
9f0ea7d4 | 563 | { |
e71627cb SP |
564 | const char *xpath = |
565 | "./match-condition[condition='frr-zebra-route-map:source-protocol']"; | |
07d030ea RZ |
566 | |
567 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
568 | ||
569 | return nb_cli_apply_changes(vty, NULL); | |
9f0ea7d4 DS |
570 | } |
571 | ||
ca77b518 | 572 | DEFPY_YANG( |
07d030ea RZ |
573 | match_source_instance, match_source_instance_cmd, |
574 | "match source-instance (0-255)$instance", | |
575 | MATCH_STR | |
576 | "Match the protocol's instance number\n" | |
577 | "The instance number\n") | |
633a66a5 | 578 | { |
e71627cb SP |
579 | const char *xpath = |
580 | "./match-condition[condition='frr-zebra-route-map:source-instance']"; | |
07d030ea RZ |
581 | char xpath_value[XPATH_MAXLEN]; |
582 | ||
583 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
584 | snprintf(xpath_value, sizeof(xpath_value), | |
e71627cb SP |
585 | "%s/rmap-match-condition/frr-zebra-route-map:source-instance", |
586 | xpath); | |
07d030ea | 587 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, instance_str); |
633a66a5 | 588 | |
07d030ea | 589 | return nb_cli_apply_changes(vty, NULL); |
633a66a5 DS |
590 | } |
591 | ||
ca77b518 | 592 | DEFPY_YANG( |
07d030ea RZ |
593 | no_match_source_instance, no_match_source_instance_cmd, |
594 | "no match source-instance [(0-255)]", | |
595 | NO_STR MATCH_STR | |
596 | "Match the protocol's instance number\n" | |
597 | "The instance number\n") | |
633a66a5 | 598 | { |
e71627cb SP |
599 | const char *xpath = |
600 | "./match-condition[condition='frr-zebra-route-map:source-instance']"; | |
07d030ea RZ |
601 | |
602 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
633a66a5 | 603 | |
07d030ea | 604 | return nb_cli_apply_changes(vty, NULL); |
633a66a5 DS |
605 | } |
606 | ||
5921ef9a PJ |
607 | /* set functions */ |
608 | ||
ca77b518 | 609 | DEFPY_YANG( |
07d030ea RZ |
610 | set_src, set_src_cmd, |
611 | "set src <A.B.C.D$addrv4|X:X::X:X$addrv6>", | |
612 | SET_STR | |
613 | "src address for route\n" | |
614 | "IPv4 src address\n" | |
615 | "IPv6 src address\n") | |
5921ef9a | 616 | { |
e71627cb SP |
617 | const char *xpath = |
618 | "./set-action[action='frr-zebra-route-map:src-address']"; | |
07d030ea RZ |
619 | char xpath_value[XPATH_MAXLEN]; |
620 | ||
621 | nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); | |
622 | if (addrv4_str) { | |
e71627cb SP |
623 | snprintf( |
624 | xpath_value, sizeof(xpath_value), | |
625 | "%s/rmap-set-action/frr-zebra-route-map:ipv4-src-address", | |
626 | xpath); | |
07d030ea RZ |
627 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, |
628 | addrv4_str); | |
d62a17ae | 629 | } else { |
e71627cb SP |
630 | snprintf( |
631 | xpath_value, sizeof(xpath_value), | |
632 | "%s/rmap-set-action/frr-zebra-route-map:ipv6-src-address", | |
633 | xpath); | |
07d030ea RZ |
634 | nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, |
635 | addrv6_str); | |
d62a17ae | 636 | } |
637 | ||
07d030ea | 638 | return nb_cli_apply_changes(vty, NULL); |
5921ef9a PJ |
639 | } |
640 | ||
ca77b518 | 641 | DEFPY_YANG( |
07d030ea RZ |
642 | no_set_src, no_set_src_cmd, |
643 | "no set src [<A.B.C.D|X:X::X:X>]", | |
644 | NO_STR | |
645 | SET_STR | |
646 | "Source address for route\n" | |
647 | "IPv4 address\n" | |
648 | "IPv6 address\n") | |
5921ef9a | 649 | { |
e71627cb SP |
650 | const char *xpath = |
651 | "./set-action[action='frr-zebra-route-map:src-address']"; | |
07d030ea RZ |
652 | |
653 | nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); | |
654 | ||
655 | return nb_cli_apply_changes(vty, NULL); | |
5921ef9a PJ |
656 | } |
657 | ||
e71627cb | 658 | DEFUN_YANG (zebra_route_map_timer, |
518f0eb1 | 659 | zebra_route_map_timer_cmd, |
6147e2c6 | 660 | "zebra route-map delay-timer (0-600)", |
41e7fb80 | 661 | ZEBRA_STR |
16cedbb0 | 662 | "Set route-map parameters\n" |
9f0ea7d4 | 663 | "Time to wait before route-map updates are processed\n" |
3d34678f | 664 | "0 means route-map changes are run immediately instead of delaying\n") |
518f0eb1 | 665 | { |
d62a17ae | 666 | int idx_number = 3; |
d7c0a89a | 667 | uint32_t rmap_delay_timer; |
518f0eb1 | 668 | |
d62a17ae | 669 | rmap_delay_timer = strtoul(argv[idx_number]->arg, NULL, 10); |
670 | zebra_route_map_set_delay_timer(rmap_delay_timer); | |
518f0eb1 | 671 | |
d62a17ae | 672 | return (CMD_SUCCESS); |
518f0eb1 DS |
673 | } |
674 | ||
e71627cb | 675 | DEFUN_YANG (no_zebra_route_map_timer, |
518f0eb1 | 676 | no_zebra_route_map_timer_cmd, |
7757e5e1 | 677 | "no zebra route-map delay-timer [(0-600)]", |
518f0eb1 | 678 | NO_STR |
41e7fb80 | 679 | ZEBRA_STR |
16cedbb0 | 680 | "Set route-map parameters\n" |
7757e5e1 | 681 | "Reset delay-timer to default value, 30 secs\n" |
3d34678f | 682 | "0 means route-map changes are run immediately instead of delaying\n") |
518f0eb1 | 683 | { |
d62a17ae | 684 | zebra_route_map_set_delay_timer(ZEBRA_RMAP_DEFAULT_UPDATE_TIMER); |
518f0eb1 | 685 | |
d62a17ae | 686 | return (CMD_SUCCESS); |
518f0eb1 DS |
687 | } |
688 | ||
ca77b518 | 689 | DEFPY_YANG (ip_protocol, |
518f0eb1 | 690 | ip_protocol_cmd, |
214e5c26 | 691 | "ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA |
692 | " $proto route-map ROUTE-MAP$rmap", | |
9f0ea7d4 DS |
693 | IP_STR |
694 | "Filter routing info exchanged between zebra and protocol\n" | |
ab0181ee | 695 | FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA |
7757e5e1 | 696 | "Specify route-map\n" |
518f0eb1 DS |
697 | "Route map name\n") |
698 | { | |
214e5c26 | 699 | int ret, rtype; |
700 | ||
bf8ba84c DS |
701 | assert(proto); |
702 | assert(rmap); | |
703 | ||
0cbed951 | 704 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 705 | |
706 | if (!zvrf) | |
707 | return CMD_WARNING; | |
d62a17ae | 708 | |
709 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 710 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 711 | else |
214e5c26 | 712 | rtype = proto_name2num(proto); |
713 | if (rtype < 0) { | |
d62a17ae | 714 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
715 | return CMD_WARNING_CONFIG_FAILED; | |
716 | } | |
518f0eb1 | 717 | |
214e5c26 | 718 | ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); |
b84c7253 | 719 | |
214e5c26 | 720 | return ret; |
518f0eb1 DS |
721 | } |
722 | ||
ca77b518 | 723 | DEFPY_YANG (no_ip_protocol, |
518f0eb1 | 724 | no_ip_protocol_cmd, |
214e5c26 | 725 | "no ip protocol " FRR_IP_PROTOCOL_MAP_STR_ZEBRA |
726 | " $proto [route-map ROUTE-MAP$rmap]", | |
518f0eb1 | 727 | NO_STR |
9f0ea7d4 DS |
728 | IP_STR |
729 | "Stop filtering routing info between zebra and protocol\n" | |
ab0181ee | 730 | FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA |
214e5c26 | 731 | "Specify route-map\n" |
7757e5e1 | 732 | "Route map name\n") |
518f0eb1 | 733 | { |
214e5c26 | 734 | int ret, rtype; |
735 | ||
bf8ba84c DS |
736 | assert(proto); |
737 | ||
0cbed951 | 738 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 739 | |
740 | if (!zvrf) | |
741 | return CMD_WARNING; | |
518f0eb1 | 742 | |
d62a17ae | 743 | if (strcasecmp(proto, "any") == 0) |
214e5c26 | 744 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 745 | else |
214e5c26 | 746 | rtype = proto_name2num(proto); |
747 | if (rtype < 0) { | |
d62a17ae | 748 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
749 | return CMD_WARNING_CONFIG_FAILED; | |
750 | } | |
7757e5e1 | 751 | |
214e5c26 | 752 | ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP, SAFI_UNICAST); |
518f0eb1 | 753 | |
214e5c26 | 754 | return ret; |
518f0eb1 DS |
755 | } |
756 | ||
ca77b518 | 757 | DEFPY_YANG (show_ip_protocol, |
518f0eb1 | 758 | show_ip_protocol_cmd, |
7cf16e19 | 759 | "show ip protocol [vrf <NAME$vrf_name|all$vrf_all>]", |
760 | SHOW_STR | |
761 | IP_STR | |
762 | "IP protocol filtering status\n" | |
763 | VRF_FULL_CMD_HELP_STR) | |
518f0eb1 | 764 | { |
7cf16e19 | 765 | int ret = show_proto_rm(vty, AFI_IP, vrf_all, vrf_name); |
518f0eb1 | 766 | |
7cf16e19 | 767 | return ret; |
518f0eb1 DS |
768 | } |
769 | ||
ca77b518 | 770 | DEFPY_YANG (ipv6_protocol, |
0aabccc0 | 771 | ipv6_protocol_cmd, |
214e5c26 | 772 | "ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA |
773 | " $proto route-map ROUTE-MAP$rmap", | |
0aabccc0 DD |
774 | IP6_STR |
775 | "Filter IPv6 routing info exchanged between zebra and protocol\n" | |
ab0181ee | 776 | FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA |
214e5c26 | 777 | "Specify route-map\n" |
0aabccc0 DD |
778 | "Route map name\n") |
779 | { | |
214e5c26 | 780 | int ret, rtype; |
781 | ||
bf8ba84c DS |
782 | assert(rmap); |
783 | assert(proto); | |
784 | ||
0cbed951 | 785 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 786 | |
787 | if (!zvrf) | |
788 | return CMD_WARNING; | |
d62a17ae | 789 | |
790 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 791 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 792 | else |
214e5c26 | 793 | rtype = proto_name2num(proto); |
794 | if (rtype < 0) { | |
d62a17ae | 795 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
796 | return CMD_WARNING_CONFIG_FAILED; | |
797 | } | |
0aabccc0 | 798 | |
214e5c26 | 799 | ret = ip_protocol_rm_add(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); |
b84c7253 | 800 | |
214e5c26 | 801 | return ret; |
0aabccc0 DD |
802 | } |
803 | ||
ca77b518 | 804 | DEFPY_YANG (no_ipv6_protocol, |
0aabccc0 | 805 | no_ipv6_protocol_cmd, |
214e5c26 | 806 | "no ipv6 protocol " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA |
807 | " $proto [route-map ROUTE-MAP$rmap]", | |
0aabccc0 DD |
808 | NO_STR |
809 | IP6_STR | |
810 | "Stop filtering IPv6 routing info between zebra and protocol\n" | |
ab0181ee | 811 | FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA |
214e5c26 | 812 | "Specify route-map\n" |
7757e5e1 | 813 | "Route map name\n") |
0aabccc0 | 814 | { |
214e5c26 | 815 | int ret, rtype; |
816 | ||
bf8ba84c DS |
817 | assert(proto); |
818 | ||
0cbed951 | 819 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 820 | |
821 | if (!zvrf) | |
822 | return CMD_WARNING; | |
d62a17ae | 823 | |
824 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 825 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 826 | else |
214e5c26 | 827 | rtype = proto_name2num(proto); |
828 | if (rtype < 0) { | |
d62a17ae | 829 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
830 | return CMD_WARNING_CONFIG_FAILED; | |
831 | } | |
b84c7253 | 832 | |
214e5c26 | 833 | ret = ip_protocol_rm_del(zvrf, rmap, rtype, AFI_IP6, SAFI_UNICAST); |
b84c7253 | 834 | |
214e5c26 | 835 | return ret; |
0aabccc0 DD |
836 | } |
837 | ||
ca77b518 | 838 | DEFPY_YANG (show_ipv6_protocol, |
0aabccc0 | 839 | show_ipv6_protocol_cmd, |
7cf16e19 | 840 | "show ipv6 protocol [vrf <NAME$vrf_name|all$vrf_all>]", |
841 | SHOW_STR | |
842 | IP6_STR | |
843 | "IPv6 protocol filtering status\n" | |
844 | VRF_FULL_CMD_HELP_STR) | |
0aabccc0 | 845 | { |
7cf16e19 | 846 | int ret = show_proto_rm(vty, AFI_IP6, vrf_all, vrf_name); |
0aabccc0 | 847 | |
7cf16e19 | 848 | return ret; |
0aabccc0 DD |
849 | } |
850 | ||
ca77b518 | 851 | DEFPY_YANG (ip_protocol_nht_rmap, |
9f0ea7d4 | 852 | ip_protocol_nht_rmap_cmd, |
214e5c26 | 853 | "ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA |
854 | " $proto route-map ROUTE-MAP$rmap", | |
9f0ea7d4 DS |
855 | IP_STR |
856 | "Filter Next Hop tracking route resolution\n" | |
ab0181ee | 857 | FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA |
7757e5e1 | 858 | "Specify route map\n" |
9f0ea7d4 DS |
859 | "Route map name\n") |
860 | { | |
214e5c26 | 861 | |
862 | int ret, rtype; | |
863 | ||
bf8ba84c DS |
864 | assert(proto); |
865 | assert(rmap); | |
866 | ||
0cbed951 | 867 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 868 | |
869 | if (!zvrf) | |
870 | return CMD_WARNING; | |
d62a17ae | 871 | |
872 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 873 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 874 | else |
214e5c26 | 875 | rtype = proto_name2num(proto); |
876 | if (rtype < 0) { | |
d62a17ae | 877 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
878 | return CMD_WARNING_CONFIG_FAILED; | |
879 | } | |
6d53d7b1 | 880 | |
214e5c26 | 881 | ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP); |
9f0ea7d4 | 882 | |
214e5c26 | 883 | return ret; |
9f0ea7d4 DS |
884 | } |
885 | ||
ca77b518 | 886 | DEFPY_YANG (no_ip_protocol_nht_rmap, |
9f0ea7d4 | 887 | no_ip_protocol_nht_rmap_cmd, |
214e5c26 | 888 | "no ip nht " FRR_IP_PROTOCOL_MAP_STR_ZEBRA |
889 | " $proto route-map [ROUTE-MAP$rmap]", | |
9f0ea7d4 DS |
890 | NO_STR |
891 | IP_STR | |
892 | "Filter Next Hop tracking route resolution\n" | |
3b14d86e | 893 | FRR_IP_PROTOCOL_MAP_HELP_STR_ZEBRA |
7757e5e1 QY |
894 | "Specify route map\n" |
895 | "Route map name\n") | |
9f0ea7d4 | 896 | { |
214e5c26 | 897 | int ret, rtype; |
55cb6743 | 898 | |
bf8ba84c DS |
899 | assert(proto); |
900 | ||
0cbed951 | 901 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
9f0ea7d4 | 902 | |
214e5c26 | 903 | if (!zvrf) |
904 | return CMD_WARNING; | |
905 | ||
906 | if (strcasecmp(proto, "any") == 0) | |
907 | rtype = ZEBRA_ROUTE_MAX; | |
908 | else | |
909 | rtype = proto_name2num(proto); | |
910 | if (rtype < 0) { | |
d62a17ae | 911 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
912 | return CMD_WARNING_CONFIG_FAILED; | |
913 | } | |
55cb6743 | 914 | |
214e5c26 | 915 | ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP); |
9f0ea7d4 | 916 | |
214e5c26 | 917 | return ret; |
9f0ea7d4 DS |
918 | } |
919 | ||
ca77b518 | 920 | DEFPY_YANG (show_ip_protocol_nht, |
9f0ea7d4 | 921 | show_ip_protocol_nht_cmd, |
63e7deba | 922 | "show ip nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", |
3a2d747c QY |
923 | SHOW_STR |
924 | IP_STR | |
63e7deba SPG |
925 | "IPv4 nexthop tracking table\n" |
926 | "IPv4 Next Hop tracking filtering status\n" | |
927 | VRF_CMD_HELP_STR | |
928 | "All VRFs\n" | |
929 | JSON_STR) | |
9f0ea7d4 | 930 | { |
63e7deba SPG |
931 | int ret; |
932 | bool uj = use_json(argc, argv); | |
933 | ||
934 | ret = show_nht_rm(vty, AFI_IP, vrf_all, vrf_name, uj); | |
9f0ea7d4 | 935 | |
7cf16e19 | 936 | return ret; |
9f0ea7d4 DS |
937 | } |
938 | ||
ca77b518 | 939 | DEFPY_YANG (ipv6_protocol_nht_rmap, |
9f0ea7d4 | 940 | ipv6_protocol_nht_rmap_cmd, |
214e5c26 | 941 | "ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA |
942 | " $proto route-map ROUTE-MAP$rmap", | |
9f0ea7d4 DS |
943 | IP6_STR |
944 | "Filter Next Hop tracking route resolution\n" | |
ab0181ee | 945 | FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA |
7757e5e1 | 946 | "Specify route map\n" |
9f0ea7d4 DS |
947 | "Route map name\n") |
948 | { | |
214e5c26 | 949 | int ret, rtype; |
950 | ||
bf8ba84c DS |
951 | assert(rmap); |
952 | assert(proto); | |
953 | ||
0cbed951 | 954 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 955 | |
956 | if (!zvrf) | |
957 | return CMD_WARNING; | |
d62a17ae | 958 | |
959 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 960 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 961 | else |
214e5c26 | 962 | rtype = proto_name2num(proto); |
963 | if (rtype < 0) { | |
d62a17ae | 964 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
965 | return CMD_WARNING_CONFIG_FAILED; | |
966 | } | |
6d53d7b1 | 967 | |
214e5c26 | 968 | ret = ip_nht_rm_add(zvrf, rmap, rtype, AFI_IP6); |
6d53d7b1 | 969 | |
214e5c26 | 970 | return ret; |
9f0ea7d4 DS |
971 | } |
972 | ||
ca77b518 | 973 | DEFPY_YANG (no_ipv6_protocol_nht_rmap, |
9f0ea7d4 | 974 | no_ipv6_protocol_nht_rmap_cmd, |
214e5c26 | 975 | "no ipv6 nht " FRR_IP6_PROTOCOL_MAP_STR_ZEBRA |
976 | " $proto [route-map ROUTE-MAP$rmap]", | |
9f0ea7d4 DS |
977 | NO_STR |
978 | IP6_STR | |
979 | "Filter Next Hop tracking route resolution\n" | |
3b14d86e | 980 | FRR_IP6_PROTOCOL_MAP_HELP_STR_ZEBRA |
7757e5e1 QY |
981 | "Specify route map\n" |
982 | "Route map name\n") | |
9f0ea7d4 | 983 | { |
214e5c26 | 984 | int ret, rtype; |
985 | ||
bf8ba84c DS |
986 | assert(proto); |
987 | ||
0cbed951 | 988 | ZEBRA_DECLVAR_CONTEXT_VRF(vrf, zvrf); |
214e5c26 | 989 | |
990 | if (!zvrf) | |
991 | return CMD_WARNING; | |
d62a17ae | 992 | |
993 | if (strcasecmp(proto, "any") == 0) | |
214e5c26 | 994 | rtype = ZEBRA_ROUTE_MAX; |
d62a17ae | 995 | else |
214e5c26 | 996 | rtype = proto_name2num(proto); |
997 | if (rtype < 0) { | |
d62a17ae | 998 | vty_out(vty, "invalid protocol name \"%s\"\n", proto); |
999 | return CMD_WARNING_CONFIG_FAILED; | |
1000 | } | |
9f0ea7d4 | 1001 | |
214e5c26 | 1002 | ret = ip_nht_rm_del(zvrf, rmap, rtype, AFI_IP6); |
813d4307 | 1003 | |
214e5c26 | 1004 | return ret; |
9f0ea7d4 DS |
1005 | } |
1006 | ||
ca77b518 | 1007 | DEFPY_YANG (show_ipv6_protocol_nht, |
9f0ea7d4 | 1008 | show_ipv6_protocol_nht_cmd, |
63e7deba | 1009 | "show ipv6 nht route-map [vrf <NAME$vrf_name|all$vrf_all>] [json]", |
3a2d747c QY |
1010 | SHOW_STR |
1011 | IP6_STR | |
63e7deba SPG |
1012 | "IPv6 nexthop tracking table\n" |
1013 | "IPv6 Next Hop tracking filtering status\n" | |
1014 | VRF_CMD_HELP_STR | |
1015 | "All VRFs\n" | |
1016 | JSON_STR) | |
9f0ea7d4 | 1017 | { |
63e7deba SPG |
1018 | int ret; |
1019 | bool uj = use_json(argc, argv); | |
1020 | ||
1021 | ret = show_nht_rm(vty, AFI_IP6, vrf_all, vrf_name, uj); | |
9f0ea7d4 | 1022 | |
7cf16e19 | 1023 | return ret; |
9f0ea7d4 DS |
1024 | } |
1025 | ||
5921ef9a PJ |
1026 | /*XXXXXXXXXXXXXXXXXXXXXXXXXXXX*/ |
1027 | ||
1028 | /* `match ip next-hop IP_ACCESS_LIST' */ | |
1029 | ||
1030 | /* Match function return 1 if match is success else return zero. */ | |
b68885f9 | 1031 | static enum route_map_cmd_result_t |
1782514f | 1032 | route_match_ip_next_hop(void *rule, const struct prefix *prefix, void *object) |
d62a17ae | 1033 | { |
1034 | struct access_list *alist; | |
1035 | struct nh_rmap_obj *nh_data; | |
1036 | struct prefix_ipv4 p; | |
1037 | ||
1782514f DS |
1038 | nh_data = object; |
1039 | if (!nh_data) | |
1040 | return RMAP_NOMATCH; | |
d62a17ae | 1041 | |
1782514f DS |
1042 | switch (nh_data->nexthop->type) { |
1043 | case NEXTHOP_TYPE_IFINDEX: | |
1044 | /* Interface routes can't match ip next-hop */ | |
1045 | return RMAP_NOMATCH; | |
1046 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
1047 | case NEXTHOP_TYPE_IPV4: | |
1048 | p.family = AF_INET; | |
1049 | p.prefix = nh_data->nexthop->gate.ipv4; | |
1050 | p.prefixlen = IPV4_MAX_BITLEN; | |
1051 | break; | |
1052 | default: | |
1053 | return RMAP_NOMATCH; | |
d62a17ae | 1054 | } |
1782514f DS |
1055 | alist = access_list_lookup(AFI_IP, (char *)rule); |
1056 | if (alist == NULL) | |
1057 | return RMAP_NOMATCH; | |
1058 | ||
1059 | return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH | |
1060 | : RMAP_MATCH); | |
5921ef9a PJ |
1061 | } |
1062 | ||
1063 | /* Route map `ip next-hop' match statement. `arg' should be | |
1064 | access-list name. */ | |
d62a17ae | 1065 | static void *route_match_ip_next_hop_compile(const char *arg) |
5921ef9a | 1066 | { |
d62a17ae | 1067 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); |
5921ef9a PJ |
1068 | } |
1069 | ||
1070 | /* Free route map's compiled `. */ | |
d62a17ae | 1071 | static void route_match_ip_next_hop_free(void *rule) |
5921ef9a | 1072 | { |
d62a17ae | 1073 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
1074 | } |
1075 | ||
1076 | /* Route map commands for ip next-hop matching. */ | |
364deb04 DL |
1077 | static const struct route_map_rule_cmd route_match_ip_next_hop_cmd = { |
1078 | "ip next-hop", | |
1079 | route_match_ip_next_hop, | |
1080 | route_match_ip_next_hop_compile, | |
1081 | route_match_ip_next_hop_free | |
1082 | }; | |
6b0655a2 | 1083 | |
5921ef9a PJ |
1084 | /* `match ip next-hop prefix-list PREFIX_LIST' */ |
1085 | ||
b68885f9 | 1086 | static enum route_map_cmd_result_t |
123214ef | 1087 | route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix, |
1782514f | 1088 | void *object) |
5921ef9a | 1089 | { |
d62a17ae | 1090 | struct prefix_list *plist; |
1091 | struct nh_rmap_obj *nh_data; | |
1092 | struct prefix_ipv4 p; | |
1093 | ||
1782514f DS |
1094 | nh_data = (struct nh_rmap_obj *)object; |
1095 | if (!nh_data) | |
1096 | return RMAP_NOMATCH; | |
d62a17ae | 1097 | |
1782514f DS |
1098 | switch (nh_data->nexthop->type) { |
1099 | case NEXTHOP_TYPE_IFINDEX: | |
1100 | /* Interface routes can't match ip next-hop */ | |
1101 | return RMAP_NOMATCH; | |
1102 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
1103 | case NEXTHOP_TYPE_IPV4: | |
1104 | p.family = AF_INET; | |
1105 | p.prefix = nh_data->nexthop->gate.ipv4; | |
1106 | p.prefixlen = IPV4_MAX_BITLEN; | |
1107 | break; | |
1108 | default: | |
1109 | return RMAP_NOMATCH; | |
d62a17ae | 1110 | } |
1782514f DS |
1111 | plist = prefix_list_lookup(AFI_IP, (char *)rule); |
1112 | if (plist == NULL) | |
1113 | return RMAP_NOMATCH; | |
1114 | ||
1115 | return (prefix_list_apply(plist, &p) == PREFIX_DENY ? RMAP_NOMATCH | |
1116 | : RMAP_MATCH); | |
5921ef9a PJ |
1117 | } |
1118 | ||
d62a17ae | 1119 | static void *route_match_ip_next_hop_prefix_list_compile(const char *arg) |
5921ef9a | 1120 | { |
d62a17ae | 1121 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); |
5921ef9a PJ |
1122 | } |
1123 | ||
d62a17ae | 1124 | static void route_match_ip_next_hop_prefix_list_free(void *rule) |
5921ef9a | 1125 | { |
d62a17ae | 1126 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
1127 | } |
1128 | ||
364deb04 DL |
1129 | static const struct route_map_rule_cmd |
1130 | route_match_ip_next_hop_prefix_list_cmd = { | |
1131 | "ip next-hop prefix-list", | |
1132 | route_match_ip_next_hop_prefix_list, | |
d62a17ae | 1133 | route_match_ip_next_hop_prefix_list_compile, |
364deb04 DL |
1134 | route_match_ip_next_hop_prefix_list_free |
1135 | }; | |
6b0655a2 | 1136 | |
5921ef9a PJ |
1137 | /* `match ip address IP_ACCESS_LIST' */ |
1138 | ||
1139 | /* Match function should return 1 if match is success else return | |
1140 | zero. */ | |
b68885f9 LK |
1141 | static enum route_map_cmd_result_t |
1142 | route_match_address(afi_t afi, void *rule, const struct prefix *prefix, | |
1782514f | 1143 | void *object) |
5921ef9a | 1144 | { |
d62a17ae | 1145 | struct access_list *alist; |
1146 | ||
1782514f DS |
1147 | alist = access_list_lookup(afi, (char *)rule); |
1148 | if (alist == NULL) | |
1149 | return RMAP_NOMATCH; | |
5921ef9a | 1150 | |
1782514f DS |
1151 | return (access_list_apply(alist, prefix) == FILTER_DENY ? RMAP_NOMATCH |
1152 | : RMAP_MATCH); | |
5921ef9a PJ |
1153 | } |
1154 | ||
b68885f9 | 1155 | static enum route_map_cmd_result_t |
1782514f | 1156 | route_match_ip_address(void *rule, const struct prefix *prefix, void *object) |
86405f9e | 1157 | { |
1782514f | 1158 | return route_match_address(AFI_IP, rule, prefix, object); |
86405f9e DS |
1159 | } |
1160 | ||
b68885f9 | 1161 | static enum route_map_cmd_result_t |
1782514f | 1162 | route_match_ipv6_address(void *rule, const struct prefix *prefix, void *object) |
86405f9e | 1163 | { |
1782514f | 1164 | return route_match_address(AFI_IP6, rule, prefix, object); |
86405f9e DS |
1165 | } |
1166 | ||
5921ef9a PJ |
1167 | /* Route map `ip address' match statement. `arg' should be |
1168 | access-list name. */ | |
86405f9e | 1169 | static void *route_match_address_compile(const char *arg) |
5921ef9a | 1170 | { |
d62a17ae | 1171 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); |
5921ef9a PJ |
1172 | } |
1173 | ||
1174 | /* Free route map's compiled `ip address' value. */ | |
86405f9e | 1175 | static void route_match_address_free(void *rule) |
5921ef9a | 1176 | { |
d62a17ae | 1177 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
1178 | } |
1179 | ||
1180 | /* Route map commands for ip address matching. */ | |
364deb04 DL |
1181 | static const struct route_map_rule_cmd route_match_ip_address_cmd = { |
1182 | "ip address", | |
1183 | route_match_ip_address, | |
1184 | route_match_address_compile, | |
1185 | route_match_address_free | |
1186 | }; | |
86405f9e DS |
1187 | |
1188 | /* Route map commands for ipv6 address matching. */ | |
364deb04 DL |
1189 | static const struct route_map_rule_cmd route_match_ipv6_address_cmd = { |
1190 | "ipv6 address", | |
1191 | route_match_ipv6_address, | |
1192 | route_match_address_compile, | |
1193 | route_match_address_free | |
1194 | }; | |
6b0655a2 | 1195 | |
5921ef9a PJ |
1196 | /* `match ip address prefix-list PREFIX_LIST' */ |
1197 | ||
b68885f9 | 1198 | static enum route_map_cmd_result_t |
01ba4505 | 1199 | route_match_address_prefix_list(void *rule, const struct prefix *prefix, |
1782514f | 1200 | void *object, afi_t afi) |
5921ef9a | 1201 | { |
d62a17ae | 1202 | struct prefix_list *plist; |
1203 | ||
1782514f DS |
1204 | plist = prefix_list_lookup(afi, (char *)rule); |
1205 | if (plist == NULL) | |
1206 | return RMAP_NOMATCH; | |
5921ef9a | 1207 | |
1782514f DS |
1208 | return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH |
1209 | : RMAP_MATCH); | |
5921ef9a PJ |
1210 | } |
1211 | ||
b68885f9 | 1212 | static enum route_map_cmd_result_t |
01ba4505 | 1213 | route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix, |
1782514f | 1214 | void *object) |
01ba4505 | 1215 | { |
1782514f | 1216 | return (route_match_address_prefix_list(rule, prefix, object, AFI_IP)); |
01ba4505 | 1217 | } |
1218 | ||
1219 | static void *route_match_address_prefix_list_compile(const char *arg) | |
5921ef9a | 1220 | { |
d62a17ae | 1221 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); |
5921ef9a PJ |
1222 | } |
1223 | ||
01ba4505 | 1224 | static void route_match_address_prefix_list_free(void *rule) |
5921ef9a | 1225 | { |
d62a17ae | 1226 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
1227 | } |
1228 | ||
364deb04 DL |
1229 | static const struct route_map_rule_cmd |
1230 | route_match_ip_address_prefix_list_cmd = { | |
1231 | "ip address prefix-list", | |
1232 | route_match_ip_address_prefix_list, | |
01ba4505 | 1233 | route_match_address_prefix_list_compile, |
364deb04 DL |
1234 | route_match_address_prefix_list_free |
1235 | }; | |
01ba4505 | 1236 | |
b68885f9 | 1237 | static enum route_map_cmd_result_t |
01ba4505 | 1238 | route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix, |
1782514f | 1239 | void *object) |
01ba4505 | 1240 | { |
1782514f | 1241 | return (route_match_address_prefix_list(rule, prefix, object, AFI_IP6)); |
01ba4505 | 1242 | } |
5921ef9a | 1243 | |
364deb04 DL |
1244 | static const struct route_map_rule_cmd |
1245 | route_match_ipv6_address_prefix_list_cmd = { | |
1246 | "ipv6 address prefix-list", | |
1247 | route_match_ipv6_address_prefix_list, | |
01ba4505 | 1248 | route_match_address_prefix_list_compile, |
364deb04 DL |
1249 | route_match_address_prefix_list_free |
1250 | }; | |
6b0655a2 | 1251 | |
b6c0e913 DA |
1252 | /* `match ipv6 next-hop type <TYPE>' */ |
1253 | ||
b68885f9 | 1254 | static enum route_map_cmd_result_t |
b6c0e913 | 1255 | route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix, |
1782514f | 1256 | void *object) |
b6c0e913 DA |
1257 | { |
1258 | struct nh_rmap_obj *nh_data; | |
1259 | ||
1782514f | 1260 | if (prefix->family == AF_INET6) { |
b6c0e913 DA |
1261 | nh_data = (struct nh_rmap_obj *)object; |
1262 | if (!nh_data) | |
b68885f9 | 1263 | return RMAP_NOMATCH; |
b6c0e913 DA |
1264 | |
1265 | if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) | |
1266 | return RMAP_MATCH; | |
1267 | } | |
1782514f | 1268 | |
b6c0e913 DA |
1269 | return RMAP_NOMATCH; |
1270 | } | |
1271 | ||
1272 | static void *route_match_ipv6_next_hop_type_compile(const char *arg) | |
1273 | { | |
1274 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); | |
1275 | } | |
1276 | ||
1277 | static void route_match_ipv6_next_hop_type_free(void *rule) | |
1278 | { | |
1279 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); | |
1280 | } | |
1281 | ||
364deb04 DL |
1282 | static const struct route_map_rule_cmd |
1283 | route_match_ipv6_next_hop_type_cmd = { | |
1284 | "ipv6 next-hop type", | |
1285 | route_match_ipv6_next_hop_type, | |
b6c0e913 | 1286 | route_match_ipv6_next_hop_type_compile, |
364deb04 DL |
1287 | route_match_ipv6_next_hop_type_free |
1288 | }; | |
b6c0e913 | 1289 | |
9f0ea7d4 DS |
1290 | /* `match ip address prefix-len PREFIXLEN' */ |
1291 | ||
b68885f9 | 1292 | static enum route_map_cmd_result_t |
123214ef | 1293 | route_match_address_prefix_len(void *rule, const struct prefix *prefix, |
1782514f | 1294 | void *object) |
9f0ea7d4 | 1295 | { |
d7c0a89a | 1296 | uint32_t *prefixlen = (uint32_t *)rule; |
9f0ea7d4 | 1297 | |
1782514f | 1298 | return ((prefix->prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH); |
9f0ea7d4 DS |
1299 | } |
1300 | ||
5165d46f | 1301 | static void *route_match_address_prefix_len_compile(const char *arg) |
9f0ea7d4 | 1302 | { |
d7c0a89a | 1303 | uint32_t *prefix_len; |
d62a17ae | 1304 | char *endptr = NULL; |
1305 | unsigned long tmpval; | |
9f0ea7d4 | 1306 | |
d62a17ae | 1307 | /* prefix len value shoud be integer. */ |
1308 | if (!all_digit(arg)) | |
1309 | return NULL; | |
9f0ea7d4 | 1310 | |
d62a17ae | 1311 | errno = 0; |
1312 | tmpval = strtoul(arg, &endptr, 10); | |
1313 | if (*endptr != '\0' || errno || tmpval > UINT32_MAX) | |
1314 | return NULL; | |
9f0ea7d4 | 1315 | |
d7c0a89a | 1316 | prefix_len = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); |
9f0ea7d4 | 1317 | |
d62a17ae | 1318 | *prefix_len = tmpval; |
1319 | return prefix_len; | |
9f0ea7d4 DS |
1320 | } |
1321 | ||
5165d46f | 1322 | static void route_match_address_prefix_len_free(void *rule) |
9f0ea7d4 | 1323 | { |
d62a17ae | 1324 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
9f0ea7d4 DS |
1325 | } |
1326 | ||
364deb04 DL |
1327 | static const struct route_map_rule_cmd |
1328 | route_match_ip_address_prefix_len_cmd = { | |
1329 | "ip address prefix-len", | |
1330 | route_match_address_prefix_len, | |
5165d46f | 1331 | route_match_address_prefix_len_compile, |
364deb04 DL |
1332 | route_match_address_prefix_len_free |
1333 | }; | |
9f0ea7d4 | 1334 | |
364deb04 DL |
1335 | static const struct route_map_rule_cmd |
1336 | route_match_ipv6_address_prefix_len_cmd = { | |
1337 | "ipv6 address prefix-len", | |
1338 | route_match_address_prefix_len, | |
5165d46f | 1339 | route_match_address_prefix_len_compile, |
364deb04 DL |
1340 | route_match_address_prefix_len_free |
1341 | }; | |
9f0ea7d4 DS |
1342 | |
1343 | /* `match ip nexthop prefix-len PREFIXLEN' */ | |
1344 | ||
b68885f9 | 1345 | static enum route_map_cmd_result_t |
123214ef | 1346 | route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix, |
1782514f | 1347 | void *object) |
d62a17ae | 1348 | { |
d7c0a89a | 1349 | uint32_t *prefixlen = (uint32_t *)rule; |
d62a17ae | 1350 | struct nh_rmap_obj *nh_data; |
1351 | struct prefix_ipv4 p; | |
1352 | ||
1782514f DS |
1353 | nh_data = (struct nh_rmap_obj *)object; |
1354 | if (!nh_data || !nh_data->nexthop) | |
1355 | return RMAP_NOMATCH; | |
d62a17ae | 1356 | |
1782514f DS |
1357 | switch (nh_data->nexthop->type) { |
1358 | case NEXTHOP_TYPE_IFINDEX: | |
1359 | /* Interface routes can't match ip next-hop */ | |
1360 | return RMAP_NOMATCH; | |
1361 | case NEXTHOP_TYPE_IPV4_IFINDEX: | |
1362 | case NEXTHOP_TYPE_IPV4: | |
1363 | p.family = AF_INET; | |
1364 | p.prefix = nh_data->nexthop->gate.ipv4; | |
1365 | p.prefixlen = IPV4_MAX_BITLEN; | |
1366 | break; | |
1367 | default: | |
1368 | return RMAP_NOMATCH; | |
d62a17ae | 1369 | } |
1782514f | 1370 | return ((p.prefixlen == *prefixlen) ? RMAP_MATCH : RMAP_NOMATCH); |
d62a17ae | 1371 | } |
1372 | ||
364deb04 DL |
1373 | static const struct route_map_rule_cmd |
1374 | route_match_ip_nexthop_prefix_len_cmd = { | |
1375 | "ip next-hop prefix-len", | |
1376 | route_match_ip_nexthop_prefix_len, | |
5165d46f DS |
1377 | route_match_address_prefix_len_compile, /* reuse */ |
1378 | route_match_address_prefix_len_free /* reuse */ | |
9f0ea7d4 DS |
1379 | }; |
1380 | ||
b6c0e913 DA |
1381 | /* `match ip next-hop type <blackhole>' */ |
1382 | ||
b68885f9 | 1383 | static enum route_map_cmd_result_t |
b6c0e913 | 1384 | route_match_ip_next_hop_type(void *rule, const struct prefix *prefix, |
1782514f | 1385 | void *object) |
b6c0e913 DA |
1386 | { |
1387 | struct nh_rmap_obj *nh_data; | |
1388 | ||
1782514f | 1389 | if (prefix->family == AF_INET) { |
b6c0e913 DA |
1390 | nh_data = (struct nh_rmap_obj *)object; |
1391 | if (!nh_data) | |
b68885f9 | 1392 | return RMAP_NOMATCH; |
b6c0e913 DA |
1393 | |
1394 | if (nh_data->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) | |
1395 | return RMAP_MATCH; | |
1396 | } | |
1782514f | 1397 | |
b6c0e913 DA |
1398 | return RMAP_NOMATCH; |
1399 | } | |
1400 | ||
1401 | static void *route_match_ip_next_hop_type_compile(const char *arg) | |
1402 | { | |
1403 | return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); | |
1404 | } | |
1405 | ||
1406 | static void route_match_ip_next_hop_type_free(void *rule) | |
1407 | { | |
1408 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); | |
1409 | } | |
1410 | ||
364deb04 DL |
1411 | static const struct route_map_rule_cmd |
1412 | route_match_ip_next_hop_type_cmd = { | |
1413 | "ip next-hop type", | |
1414 | route_match_ip_next_hop_type, | |
b6c0e913 | 1415 | route_match_ip_next_hop_type_compile, |
364deb04 DL |
1416 | route_match_ip_next_hop_type_free |
1417 | }; | |
b6c0e913 | 1418 | |
9f0ea7d4 DS |
1419 | /* `match source-protocol PROTOCOL' */ |
1420 | ||
b68885f9 | 1421 | static enum route_map_cmd_result_t |
1782514f | 1422 | route_match_source_protocol(void *rule, const struct prefix *p, void *object) |
9f0ea7d4 | 1423 | { |
d7c0a89a | 1424 | uint32_t *rib_type = (uint32_t *)rule; |
d62a17ae | 1425 | struct nh_rmap_obj *nh_data; |
9f0ea7d4 | 1426 | |
1782514f DS |
1427 | nh_data = (struct nh_rmap_obj *)object; |
1428 | if (!nh_data) | |
1429 | return RMAP_NOMATCH; | |
9f0ea7d4 | 1430 | |
1782514f DS |
1431 | return ((nh_data->source_protocol == *rib_type) ? RMAP_MATCH |
1432 | : RMAP_NOMATCH); | |
9f0ea7d4 DS |
1433 | } |
1434 | ||
d62a17ae | 1435 | static void *route_match_source_protocol_compile(const char *arg) |
9f0ea7d4 | 1436 | { |
d7c0a89a | 1437 | uint32_t *rib_type; |
d62a17ae | 1438 | int i; |
9f0ea7d4 | 1439 | |
d62a17ae | 1440 | i = proto_name2num(arg); |
d7c0a89a | 1441 | rib_type = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t)); |
9f0ea7d4 | 1442 | |
d62a17ae | 1443 | *rib_type = i; |
9f0ea7d4 | 1444 | |
d62a17ae | 1445 | return rib_type; |
9f0ea7d4 DS |
1446 | } |
1447 | ||
d62a17ae | 1448 | static void route_match_source_protocol_free(void *rule) |
9f0ea7d4 | 1449 | { |
d62a17ae | 1450 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
9f0ea7d4 DS |
1451 | } |
1452 | ||
364deb04 DL |
1453 | static const struct route_map_rule_cmd route_match_source_protocol_cmd = { |
1454 | "source-protocol", | |
1455 | route_match_source_protocol, | |
1456 | route_match_source_protocol_compile, | |
1457 | route_match_source_protocol_free | |
1458 | }; | |
9f0ea7d4 | 1459 | |
633a66a5 | 1460 | /* `source-instance` */ |
b68885f9 | 1461 | static enum route_map_cmd_result_t |
1782514f | 1462 | route_match_source_instance(void *rule, const struct prefix *p, void *object) |
633a66a5 DS |
1463 | { |
1464 | uint8_t *instance = (uint8_t *)rule; | |
1465 | struct nh_rmap_obj *nh_data; | |
1466 | ||
633a66a5 DS |
1467 | nh_data = (struct nh_rmap_obj *)object; |
1468 | if (!nh_data) | |
b68885f9 | 1469 | return RMAP_NOMATCH; |
633a66a5 DS |
1470 | |
1471 | return (nh_data->instance == *instance) ? RMAP_MATCH : RMAP_NOMATCH; | |
1472 | } | |
1473 | ||
1474 | static void *route_match_source_instance_compile(const char *arg) | |
1475 | { | |
1476 | uint8_t *instance; | |
1477 | int i; | |
1478 | ||
1479 | i = atoi(arg); | |
1480 | instance = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint8_t)); | |
1481 | ||
1482 | *instance = i; | |
1483 | ||
1484 | return instance; | |
1485 | } | |
1486 | ||
1487 | static void route_match_source_instance_free(void *rule) | |
1488 | { | |
1489 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); | |
1490 | } | |
1491 | ||
364deb04 DL |
1492 | static const struct route_map_rule_cmd route_match_source_instance_cmd = { |
1493 | "source-instance", | |
1494 | route_match_source_instance, | |
1495 | route_match_source_instance_compile, | |
1496 | route_match_source_instance_free | |
1497 | }; | |
633a66a5 | 1498 | |
5921ef9a PJ |
1499 | /* `set src A.B.C.D' */ |
1500 | ||
1501 | /* Set src. */ | |
b68885f9 | 1502 | static enum route_map_cmd_result_t |
1782514f | 1503 | route_set_src(void *rule, const struct prefix *prefix, void *object) |
5921ef9a | 1504 | { |
d62a17ae | 1505 | struct nh_rmap_obj *nh_data; |
9f0ea7d4 | 1506 | |
1782514f DS |
1507 | nh_data = (struct nh_rmap_obj *)object; |
1508 | nh_data->nexthop->rmap_src = *(union g_addr *)rule; | |
1509 | ||
d62a17ae | 1510 | return RMAP_OKAY; |
5921ef9a PJ |
1511 | } |
1512 | ||
1513 | /* set src compilation. */ | |
d62a17ae | 1514 | static void *route_set_src_compile(const char *arg) |
5921ef9a | 1515 | { |
d62a17ae | 1516 | union g_addr src, *psrc; |
5921ef9a | 1517 | |
d62a17ae | 1518 | if ((inet_pton(AF_INET6, arg, &src.ipv6) == 1) |
17a21721 | 1519 | || (inet_pton(AF_INET, arg, &src.ipv4) == 1)) { |
d62a17ae | 1520 | psrc = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(union g_addr)); |
1521 | *psrc = src; | |
1522 | return psrc; | |
1523 | } | |
1524 | return NULL; | |
5921ef9a PJ |
1525 | } |
1526 | ||
1527 | /* Free route map's compiled `set src' value. */ | |
d62a17ae | 1528 | static void route_set_src_free(void *rule) |
5921ef9a | 1529 | { |
d62a17ae | 1530 | XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); |
5921ef9a PJ |
1531 | } |
1532 | ||
1533 | /* Set src rule structure. */ | |
364deb04 DL |
1534 | static const struct route_map_rule_cmd route_set_src_cmd = { |
1535 | "src", | |
1536 | route_set_src, | |
1537 | route_set_src_compile, | |
1538 | route_set_src_free, | |
5921ef9a PJ |
1539 | }; |
1540 | ||
d5b8c216 | 1541 | /* The function checks if the changed routemap specified by parameter rmap |
1542 | * matches the configured protocol routemaps in proto_rm table. If there is | |
1543 | * a match then rib_update_table() to process the routes. | |
1544 | */ | |
1545 | static void zebra_rib_table_rm_update(const char *rmap) | |
1546 | { | |
1547 | int i = 0; | |
1548 | struct route_table *table; | |
ac6eebce | 1549 | struct vrf *vrf = NULL; |
1550 | struct zebra_vrf *zvrf = NULL; | |
d5b8c216 | 1551 | char *rmap_name; |
54e80c76 | 1552 | struct route_map *old = NULL; |
d5b8c216 | 1553 | |
ac6eebce | 1554 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
1555 | zvrf = vrf->info; | |
1556 | if (!zvrf) | |
1557 | continue; | |
1558 | for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { | |
1559 | rmap_name = PROTO_RM_NAME(zvrf, AFI_IP, i); | |
1560 | if (rmap_name && (strcmp(rmap_name, rmap) == 0)) { | |
1561 | if (IS_ZEBRA_DEBUG_EVENT) | |
1562 | zlog_debug( | |
1563 | "%s : AFI_IP rmap %s, route type %s", | |
1564 | __func__, rmap, | |
1565 | zebra_route_string(i)); | |
1566 | ||
54e80c76 | 1567 | old = PROTO_RM_MAP(zvrf, AFI_IP, i); |
1568 | ||
ac6eebce | 1569 | PROTO_RM_MAP(zvrf, AFI_IP, i) = |
1570 | route_map_lookup_by_name(rmap_name); | |
54e80c76 | 1571 | /* old is NULL. i.e Route map creation event. |
1572 | * So update applied_counter. | |
1573 | * If Old is not NULL, i.e It may be routemap | |
1574 | * updation or deletion. | |
1575 | * So no need to update the counter. | |
1576 | */ | |
1577 | if (!old) | |
1578 | route_map_counter_increment( | |
1579 | PROTO_RM_MAP(zvrf, AFI_IP, i)); | |
ac6eebce | 1580 | /* There is single rib table for all protocols |
1581 | */ | |
cfcd844c DS |
1582 | table = zvrf->table[AFI_IP][SAFI_UNICAST]; |
1583 | if (table) { | |
1584 | rib_update_table( | |
1585 | table, | |
1586 | RIB_UPDATE_RMAP_CHANGE, | |
1587 | i); | |
d5b8c216 | 1588 | } |
1589 | } | |
ac6eebce | 1590 | rmap_name = PROTO_RM_NAME(zvrf, AFI_IP6, i); |
1591 | if (rmap_name && (strcmp(rmap_name, rmap) == 0)) { | |
1592 | if (IS_ZEBRA_DEBUG_EVENT) | |
1593 | zlog_debug( | |
1594 | "%s : AFI_IP6 rmap %s, route type %s", | |
1595 | __func__, rmap, | |
1596 | zebra_route_string(i)); | |
1597 | ||
54e80c76 | 1598 | old = PROTO_RM_MAP(zvrf, AFI_IP6, i); |
1599 | ||
ac6eebce | 1600 | PROTO_RM_MAP(zvrf, AFI_IP6, i) = |
1601 | route_map_lookup_by_name(rmap_name); | |
54e80c76 | 1602 | if (!old) |
1603 | route_map_counter_increment( | |
1604 | PROTO_RM_MAP(zvrf, AFI_IP6, i)); | |
ac6eebce | 1605 | /* There is single rib table for all protocols |
1606 | */ | |
cfcd844c DS |
1607 | table = zvrf->table[AFI_IP6][SAFI_UNICAST]; |
1608 | if (table) { | |
1609 | rib_update_table( | |
1610 | table, | |
1611 | RIB_UPDATE_RMAP_CHANGE, | |
1612 | i); | |
d5b8c216 | 1613 | } |
1614 | } | |
1615 | } | |
1616 | } | |
1617 | } | |
1618 | ||
1619 | /* The function checks if the changed routemap specified by parameter rmap | |
1620 | * matches the configured protocol routemaps in nht_rm table. If there is | |
1621 | * a match then zebra_evaluate_rnh() to process the nexthops. | |
1622 | */ | |
1623 | static void zebra_nht_rm_update(const char *rmap) | |
1624 | { | |
1625 | int i = 0; | |
ac6eebce | 1626 | struct route_table *table; |
1627 | struct vrf *vrf = NULL; | |
1628 | struct zebra_vrf *zvrf = NULL; | |
d5b8c216 | 1629 | char *rmap_name; |
1630 | char afi_ip = 0; | |
1631 | char afi_ipv6 = 0; | |
54e80c76 | 1632 | struct route_map *old = NULL; |
d5b8c216 | 1633 | |
ac6eebce | 1634 | RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { |
1635 | zvrf = vrf->info; | |
1636 | if (!zvrf) | |
1637 | continue; | |
1638 | for (i = 0; i <= ZEBRA_ROUTE_MAX; i++) { | |
1639 | rmap_name = NHT_RM_NAME(zvrf, AFI_IP, i); | |
1640 | if (rmap_name && (strcmp(rmap_name, rmap) == 0)) { | |
1641 | if (IS_ZEBRA_DEBUG_EVENT) | |
1642 | zlog_debug( | |
1643 | "%s : AFI_IP rmap %s, route type %s", | |
1644 | __func__, rmap, | |
1645 | zebra_route_string(i)); | |
1646 | ||
54e80c76 | 1647 | old = NHT_RM_MAP(zvrf, AFI_IP, i); |
1648 | ||
ac6eebce | 1649 | NHT_RM_MAP(zvrf, AFI_IP, i) = |
1650 | route_map_lookup_by_name(rmap_name); | |
54e80c76 | 1651 | if (!old) |
1652 | route_map_counter_increment( | |
1653 | NHT_RM_MAP(zvrf, AFI_IP, i)); | |
ac6eebce | 1654 | /* There is single rib table for all protocols |
1655 | */ | |
1656 | if (afi_ip == 0) { | |
1657 | table = zvrf->table[AFI_IP] | |
1658 | [SAFI_UNICAST]; | |
1659 | if (table) { | |
1660 | ||
1661 | afi_ip = 1; | |
1662 | ||
d597533a DS |
1663 | zebra_evaluate_rnh( |
1664 | zvrf, AFI_IP, 1, NULL, | |
1665 | SAFI_UNICAST); | |
ac6eebce | 1666 | } |
1667 | } | |
d5b8c216 | 1668 | } |
ac6eebce | 1669 | |
1670 | rmap_name = NHT_RM_NAME(zvrf, AFI_IP6, i); | |
1671 | if (rmap_name && (strcmp(rmap_name, rmap) == 0)) { | |
1672 | if (IS_ZEBRA_DEBUG_EVENT) | |
1673 | zlog_debug( | |
1674 | "%s : AFI_IP6 rmap %s, route type %s", | |
1675 | __func__, rmap, | |
1676 | zebra_route_string(i)); | |
1677 | ||
54e80c76 | 1678 | old = NHT_RM_MAP(zvrf, AFI_IP6, i); |
1679 | ||
ac6eebce | 1680 | NHT_RM_MAP(zvrf, AFI_IP6, i) = |
1681 | route_map_lookup_by_name(rmap_name); | |
54e80c76 | 1682 | if (!old) |
1683 | route_map_counter_increment( | |
1684 | NHT_RM_MAP(zvrf, AFI_IP6, i)); | |
ac6eebce | 1685 | /* There is single rib table for all protocols |
1686 | */ | |
1687 | if (afi_ipv6 == 0) { | |
1688 | table = zvrf->table[AFI_IP6] | |
1689 | [SAFI_UNICAST]; | |
1690 | if (table) { | |
1691 | ||
1692 | afi_ipv6 = 1; | |
1693 | ||
d597533a DS |
1694 | zebra_evaluate_rnh( |
1695 | zvrf, AFI_IP, 1, NULL, | |
1696 | SAFI_UNICAST); | |
ac6eebce | 1697 | } |
1698 | } | |
d5b8c216 | 1699 | } |
1700 | } | |
1701 | } | |
1702 | } | |
1703 | ||
46a69f10 | 1704 | static void zebra_route_map_process_update_cb(char *rmap_name) |
75a2b29d DS |
1705 | { |
1706 | if (IS_ZEBRA_DEBUG_EVENT) | |
1707 | zlog_debug("Event handler for route-map: %s", | |
1708 | rmap_name); | |
d5b8c216 | 1709 | zebra_import_table_rm_update(rmap_name); |
1710 | zebra_rib_table_rm_update(rmap_name); | |
1711 | zebra_nht_rm_update(rmap_name); | |
75a2b29d DS |
1712 | } |
1713 | ||
cc9f21da | 1714 | static void zebra_route_map_update_timer(struct thread *thread) |
518f0eb1 | 1715 | { |
d62a17ae | 1716 | if (IS_ZEBRA_DEBUG_EVENT) |
1717 | zlog_debug("Event driven route-map update triggered"); | |
518f0eb1 | 1718 | |
d62a17ae | 1719 | if (IS_ZEBRA_DEBUG_RIB_DETAILED) |
1720 | zlog_debug( | |
1721 | "%u: Routemap update-timer fired, scheduling RIB processing", | |
1722 | VRF_DEFAULT); | |
b84c7253 | 1723 | |
75a2b29d DS |
1724 | route_map_walk_update_list(zebra_route_map_process_update_cb); |
1725 | ||
1726 | /* | |
1727 | * This code needs to be updated to be: | |
1728 | * 1) VRF Aware <sigh> | |
1729 | * 2) Route-map aware | |
1730 | */ | |
518f0eb1 DS |
1731 | } |
1732 | ||
d7c0a89a | 1733 | static void zebra_route_map_set_delay_timer(uint32_t value) |
518f0eb1 | 1734 | { |
d62a17ae | 1735 | zebra_rmap_update_timer = value; |
1736 | if (!value && zebra_t_rmap_update) { | |
1737 | /* Event driven route map updates is being disabled */ | |
1738 | /* But there's a pending timer. Fire it off now */ | |
4dfcfabf DS |
1739 | THREAD_OFF(zebra_t_rmap_update); |
1740 | zebra_route_map_update_timer(NULL); | |
d62a17ae | 1741 | } |
518f0eb1 DS |
1742 | } |
1743 | ||
a2665e38 | 1744 | void zebra_routemap_finish(void) |
1745 | { | |
1746 | /* Set zebra_rmap_update_timer to 0 so that it wont schedule again */ | |
1747 | zebra_rmap_update_timer = 0; | |
1748 | /* Thread off if any scheduled already */ | |
4dfcfabf | 1749 | THREAD_OFF(zebra_t_rmap_update); |
a2665e38 | 1750 | route_map_finish(); |
1751 | } | |
1752 | ||
ac6eebce | 1753 | route_map_result_t |
f5b7e50f | 1754 | zebra_route_map_check(afi_t family, int rib_type, uint8_t instance, |
ac6eebce | 1755 | const struct prefix *p, struct nexthop *nexthop, |
1756 | struct zebra_vrf *zvrf, route_tag_t tag) | |
518f0eb1 | 1757 | { |
d62a17ae | 1758 | struct route_map *rmap = NULL; |
fd303a4b | 1759 | char *rm_name; |
b68885f9 | 1760 | route_map_result_t ret = RMAP_PERMITMATCH; |
d62a17ae | 1761 | struct nh_rmap_obj nh_obj; |
9f0ea7d4 | 1762 | |
d62a17ae | 1763 | nh_obj.nexthop = nexthop; |
ac6eebce | 1764 | nh_obj.vrf_id = nexthop->vrf_id; |
d62a17ae | 1765 | nh_obj.source_protocol = rib_type; |
633a66a5 | 1766 | nh_obj.instance = instance; |
d62a17ae | 1767 | nh_obj.metric = 0; |
1768 | nh_obj.tag = tag; | |
518f0eb1 | 1769 | |
fd303a4b DS |
1770 | if (rib_type >= 0 && rib_type < ZEBRA_ROUTE_MAX) { |
1771 | rm_name = PROTO_RM_NAME(zvrf, family, rib_type); | |
ac6eebce | 1772 | rmap = PROTO_RM_MAP(zvrf, family, rib_type); |
fd303a4b DS |
1773 | |
1774 | if (rm_name && !rmap) | |
1775 | return RMAP_DENYMATCH; | |
1776 | } | |
1777 | if (!rmap) { | |
1778 | rm_name = PROTO_RM_NAME(zvrf, family, ZEBRA_ROUTE_MAX); | |
ac6eebce | 1779 | rmap = PROTO_RM_MAP(zvrf, family, ZEBRA_ROUTE_MAX); |
fd303a4b DS |
1780 | |
1781 | if (rm_name && !rmap) | |
1782 | return RMAP_DENYMATCH; | |
1783 | } | |
d62a17ae | 1784 | if (rmap) { |
1782514f | 1785 | ret = route_map_apply(rmap, p, &nh_obj); |
d62a17ae | 1786 | } |
9f0ea7d4 | 1787 | |
d62a17ae | 1788 | return (ret); |
9f0ea7d4 DS |
1789 | } |
1790 | ||
d62a17ae | 1791 | char *zebra_get_import_table_route_map(afi_t afi, uint32_t table) |
8902474b | 1792 | { |
d62a17ae | 1793 | return zebra_import_table_routemap[afi][table]; |
8902474b DS |
1794 | } |
1795 | ||
d62a17ae | 1796 | void zebra_add_import_table_route_map(afi_t afi, const char *rmap_name, |
1797 | uint32_t table) | |
8902474b | 1798 | { |
d62a17ae | 1799 | zebra_import_table_routemap[afi][table] = |
1800 | XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap_name); | |
8902474b DS |
1801 | } |
1802 | ||
d62a17ae | 1803 | void zebra_del_import_table_route_map(afi_t afi, uint32_t table) |
8902474b | 1804 | { |
d62a17ae | 1805 | XFREE(MTYPE_ROUTE_MAP_NAME, zebra_import_table_routemap[afi][table]); |
8902474b DS |
1806 | } |
1807 | ||
1808 | route_map_result_t | |
633a66a5 | 1809 | zebra_import_table_route_map_check(int family, int re_type, uint8_t instance, |
123214ef MS |
1810 | const struct prefix *p, |
1811 | struct nexthop *nexthop, | |
633a66a5 DS |
1812 | vrf_id_t vrf_id, route_tag_t tag, |
1813 | const char *rmap_name) | |
d62a17ae | 1814 | { |
1815 | struct route_map *rmap = NULL; | |
2789041a | 1816 | route_map_result_t ret = RMAP_DENYMATCH; |
d62a17ae | 1817 | struct nh_rmap_obj nh_obj; |
1818 | ||
1819 | nh_obj.nexthop = nexthop; | |
1820 | nh_obj.vrf_id = vrf_id; | |
1821 | nh_obj.source_protocol = re_type; | |
633a66a5 | 1822 | nh_obj.instance = instance; |
d62a17ae | 1823 | nh_obj.metric = 0; |
1824 | nh_obj.tag = tag; | |
1825 | ||
1826 | if (re_type >= 0 && re_type < ZEBRA_ROUTE_MAX) | |
1827 | rmap = route_map_lookup_by_name(rmap_name); | |
1828 | if (rmap) { | |
1782514f | 1829 | ret = route_map_apply(rmap, p, &nh_obj); |
d62a17ae | 1830 | } |
8902474b | 1831 | |
d62a17ae | 1832 | return (ret); |
8902474b DS |
1833 | } |
1834 | ||
73bf60a0 | 1835 | route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto, |
123214ef | 1836 | const struct prefix *p, |
ac6eebce | 1837 | struct zebra_vrf *zvrf, |
d62a17ae | 1838 | struct route_entry *re, |
1839 | struct nexthop *nexthop) | |
9f0ea7d4 | 1840 | { |
d62a17ae | 1841 | struct route_map *rmap = NULL; |
b68885f9 | 1842 | route_map_result_t ret = RMAP_PERMITMATCH; |
d62a17ae | 1843 | struct nh_rmap_obj nh_obj; |
9f0ea7d4 | 1844 | |
d62a17ae | 1845 | nh_obj.nexthop = nexthop; |
4a7371e9 | 1846 | nh_obj.vrf_id = nexthop->vrf_id; |
d62a17ae | 1847 | nh_obj.source_protocol = re->type; |
633a66a5 | 1848 | nh_obj.instance = re->instance; |
d62a17ae | 1849 | nh_obj.metric = re->metric; |
1850 | nh_obj.tag = re->tag; | |
9f0ea7d4 | 1851 | |
d62a17ae | 1852 | if (client_proto >= 0 && client_proto < ZEBRA_ROUTE_MAX) |
73bf60a0 RW |
1853 | rmap = NHT_RM_MAP(zvrf, afi, client_proto); |
1854 | if (!rmap && NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX)) | |
1855 | rmap = NHT_RM_MAP(zvrf, afi, ZEBRA_ROUTE_MAX); | |
123214ef | 1856 | if (rmap) |
1782514f | 1857 | ret = route_map_apply(rmap, p, &nh_obj); |
518f0eb1 | 1858 | |
123214ef | 1859 | return ret; |
518f0eb1 DS |
1860 | } |
1861 | ||
d62a17ae | 1862 | static void zebra_route_map_mark_update(const char *rmap_name) |
518f0eb1 | 1863 | { |
d62a17ae | 1864 | /* rmap_update_timer of 0 means don't do route updates */ |
d33da0e0 | 1865 | if (zebra_rmap_update_timer) |
4dfcfabf | 1866 | THREAD_OFF(zebra_t_rmap_update); |
d33da0e0 DS |
1867 | |
1868 | thread_add_timer(zrouter.master, zebra_route_map_update_timer, | |
1869 | NULL, zebra_rmap_update_timer, &zebra_t_rmap_update); | |
518f0eb1 DS |
1870 | } |
1871 | ||
d62a17ae | 1872 | static void zebra_route_map_add(const char *rmap_name) |
518f0eb1 | 1873 | { |
75a2b29d DS |
1874 | if (route_map_mark_updated(rmap_name) == 0) |
1875 | zebra_route_map_mark_update(rmap_name); | |
1876 | ||
d62a17ae | 1877 | route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); |
518f0eb1 DS |
1878 | } |
1879 | ||
d62a17ae | 1880 | static void zebra_route_map_delete(const char *rmap_name) |
518f0eb1 | 1881 | { |
75a2b29d DS |
1882 | if (route_map_mark_updated(rmap_name) == 0) |
1883 | zebra_route_map_mark_update(rmap_name); | |
1884 | ||
d62a17ae | 1885 | route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_DELETED); |
518f0eb1 DS |
1886 | } |
1887 | ||
097b5973 | 1888 | static void zebra_route_map_event(const char *rmap_name) |
518f0eb1 | 1889 | { |
75a2b29d DS |
1890 | if (route_map_mark_updated(rmap_name) == 0) |
1891 | zebra_route_map_mark_update(rmap_name); | |
1892 | ||
d62a17ae | 1893 | route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); |
518f0eb1 DS |
1894 | } |
1895 | ||
cda0f501 DS |
1896 | void zebra_routemap_vrf_delete(struct zebra_vrf *zvrf) |
1897 | { | |
1898 | afi_t afi; | |
1899 | uint8_t type; | |
1900 | ||
1901 | for (afi = AFI_IP; afi < AFI_MAX; afi++) { | |
1902 | for (type = 0; type <= ZEBRA_ROUTE_MAX; type++) { | |
1903 | if (PROTO_RM_NAME(zvrf, afi, type)) | |
1904 | XFREE(MTYPE_ROUTE_MAP_NAME, | |
1905 | PROTO_RM_NAME(zvrf, afi, type)); | |
1906 | if (NHT_RM_NAME(zvrf, afi, type)) | |
1907 | XFREE(MTYPE_ROUTE_MAP_NAME, | |
1908 | NHT_RM_NAME(zvrf, afi, type)); | |
1909 | } | |
1910 | } | |
1911 | } | |
1912 | ||
518f0eb1 | 1913 | /* ip protocol configuration write function */ |
7cf16e19 | 1914 | void zebra_routemap_config_write_protocol(struct vty *vty, |
1915 | struct zebra_vrf *zvrf) | |
d62a17ae | 1916 | { |
1917 | int i; | |
7cf16e19 | 1918 | char space[2]; |
d62a17ae | 1919 | |
7cf16e19 | 1920 | memset(space, 0, sizeof(space)); |
d62a17ae | 1921 | |
7cf16e19 | 1922 | if (zvrf_id(zvrf) != VRF_DEFAULT) |
772270f3 | 1923 | snprintf(space, sizeof(space), "%s", " "); |
d62a17ae | 1924 | |
7cf16e19 | 1925 | for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { |
1926 | if (PROTO_RM_NAME(zvrf, AFI_IP, i)) | |
1927 | vty_out(vty, "%sip protocol %s route-map %s\n", space, | |
1928 | zebra_route_string(i), | |
1929 | PROTO_RM_NAME(zvrf, AFI_IP, i)); | |
1930 | ||
1931 | if (PROTO_RM_NAME(zvrf, AFI_IP6, i)) | |
1932 | vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, | |
1933 | zebra_route_string(i), | |
1934 | PROTO_RM_NAME(zvrf, AFI_IP6, i)); | |
1935 | ||
1936 | if (NHT_RM_NAME(zvrf, AFI_IP, i)) | |
1937 | vty_out(vty, "%sip nht %s route-map %s\n", space, | |
1938 | zebra_route_string(i), | |
1939 | NHT_RM_NAME(zvrf, AFI_IP, i)); | |
1940 | ||
1941 | if (NHT_RM_NAME(zvrf, AFI_IP6, i)) | |
1942 | vty_out(vty, "%sipv6 nht %s route-map %s\n", space, | |
1943 | zebra_route_string(i), | |
1944 | NHT_RM_NAME(zvrf, AFI_IP6, i)); | |
d62a17ae | 1945 | } |
1946 | ||
7cf16e19 | 1947 | if (PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) |
1948 | vty_out(vty, "%sip protocol %s route-map %s\n", space, "any", | |
1949 | PROTO_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); | |
d62a17ae | 1950 | |
7cf16e19 | 1951 | if (PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) |
1952 | vty_out(vty, "%sipv6 protocol %s route-map %s\n", space, "any", | |
1953 | PROTO_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); | |
d62a17ae | 1954 | |
7cf16e19 | 1955 | if (NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)) |
1956 | vty_out(vty, "%sip nht %s route-map %s\n", space, "any", | |
1957 | NHT_RM_NAME(zvrf, AFI_IP, ZEBRA_ROUTE_MAX)); | |
d62a17ae | 1958 | |
7cf16e19 | 1959 | if (NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)) |
1960 | vty_out(vty, "%sipv6 nht %s route-map %s\n", space, "any", | |
1961 | NHT_RM_NAME(zvrf, AFI_IP6, ZEBRA_ROUTE_MAX)); | |
d62a17ae | 1962 | |
9df81095 DS |
1963 | if (zvrf_id(zvrf) == VRF_DEFAULT |
1964 | && zebra_rmap_update_timer != ZEBRA_RMAP_DEFAULT_UPDATE_TIMER) | |
d62a17ae | 1965 | vty_out(vty, "zebra route-map delay-timer %d\n", |
1966 | zebra_rmap_update_timer); | |
1967 | } | |
1968 | ||
4d762f26 | 1969 | void zebra_route_map_init(void) |
d62a17ae | 1970 | { |
1971 | install_element(CONFIG_NODE, &ip_protocol_cmd); | |
1972 | install_element(CONFIG_NODE, &no_ip_protocol_cmd); | |
214e5c26 | 1973 | install_element(VRF_NODE, &ip_protocol_cmd); |
1974 | install_element(VRF_NODE, &no_ip_protocol_cmd); | |
d62a17ae | 1975 | install_element(VIEW_NODE, &show_ip_protocol_cmd); |
1976 | install_element(CONFIG_NODE, &ipv6_protocol_cmd); | |
1977 | install_element(CONFIG_NODE, &no_ipv6_protocol_cmd); | |
214e5c26 | 1978 | install_element(VRF_NODE, &ipv6_protocol_cmd); |
1979 | install_element(VRF_NODE, &no_ipv6_protocol_cmd); | |
d62a17ae | 1980 | install_element(VIEW_NODE, &show_ipv6_protocol_cmd); |
1981 | install_element(CONFIG_NODE, &ip_protocol_nht_rmap_cmd); | |
1982 | install_element(CONFIG_NODE, &no_ip_protocol_nht_rmap_cmd); | |
214e5c26 | 1983 | install_element(VRF_NODE, &ip_protocol_nht_rmap_cmd); |
1984 | install_element(VRF_NODE, &no_ip_protocol_nht_rmap_cmd); | |
d62a17ae | 1985 | install_element(VIEW_NODE, &show_ip_protocol_nht_cmd); |
1986 | install_element(CONFIG_NODE, &ipv6_protocol_nht_rmap_cmd); | |
1987 | install_element(CONFIG_NODE, &no_ipv6_protocol_nht_rmap_cmd); | |
214e5c26 | 1988 | install_element(VRF_NODE, &ipv6_protocol_nht_rmap_cmd); |
1989 | install_element(VRF_NODE, &no_ipv6_protocol_nht_rmap_cmd); | |
d62a17ae | 1990 | install_element(VIEW_NODE, &show_ipv6_protocol_nht_cmd); |
1991 | install_element(CONFIG_NODE, &zebra_route_map_timer_cmd); | |
1992 | install_element(CONFIG_NODE, &no_zebra_route_map_timer_cmd); | |
1993 | ||
1994 | route_map_init(); | |
1995 | ||
1996 | route_map_add_hook(zebra_route_map_add); | |
1997 | route_map_delete_hook(zebra_route_map_delete); | |
1998 | route_map_event_hook(zebra_route_map_event); | |
1999 | ||
2000 | route_map_match_interface_hook(generic_match_add); | |
2001 | route_map_no_match_interface_hook(generic_match_delete); | |
2002 | ||
2003 | route_map_match_ip_address_hook(generic_match_add); | |
2004 | route_map_no_match_ip_address_hook(generic_match_delete); | |
2005 | ||
2006 | route_map_match_ip_address_prefix_list_hook(generic_match_add); | |
2007 | route_map_no_match_ip_address_prefix_list_hook(generic_match_delete); | |
2008 | ||
2009 | route_map_match_ip_next_hop_hook(generic_match_add); | |
2010 | route_map_no_match_ip_next_hop_hook(generic_match_delete); | |
2011 | ||
2012 | route_map_match_ip_next_hop_prefix_list_hook(generic_match_add); | |
2013 | route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete); | |
2014 | ||
b6c0e913 DA |
2015 | route_map_match_ip_next_hop_type_hook(generic_match_add); |
2016 | route_map_no_match_ip_next_hop_type_hook(generic_match_delete); | |
2017 | ||
d62a17ae | 2018 | route_map_match_tag_hook(generic_match_add); |
2019 | route_map_no_match_tag_hook(generic_match_delete); | |
2020 | ||
01ba4505 | 2021 | route_map_match_ipv6_address_hook(generic_match_add); |
2022 | route_map_no_match_ipv6_address_hook(generic_match_delete); | |
2023 | ||
2024 | route_map_match_ipv6_address_prefix_list_hook(generic_match_add); | |
2025 | route_map_no_match_ipv6_address_prefix_list_hook(generic_match_delete); | |
2026 | ||
b6c0e913 DA |
2027 | route_map_match_ipv6_next_hop_type_hook(generic_match_add); |
2028 | route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete); | |
2029 | ||
d62a17ae | 2030 | route_map_install_match(&route_match_tag_cmd); |
2031 | route_map_install_match(&route_match_interface_cmd); | |
2032 | route_map_install_match(&route_match_ip_next_hop_cmd); | |
2033 | route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd); | |
2034 | route_map_install_match(&route_match_ip_address_cmd); | |
86405f9e | 2035 | route_map_install_match(&route_match_ipv6_address_cmd); |
d62a17ae | 2036 | route_map_install_match(&route_match_ip_address_prefix_list_cmd); |
01ba4505 | 2037 | route_map_install_match(&route_match_ipv6_address_prefix_list_cmd); |
d62a17ae | 2038 | route_map_install_match(&route_match_ip_address_prefix_len_cmd); |
5165d46f | 2039 | route_map_install_match(&route_match_ipv6_address_prefix_len_cmd); |
d62a17ae | 2040 | route_map_install_match(&route_match_ip_nexthop_prefix_len_cmd); |
b6c0e913 DA |
2041 | route_map_install_match(&route_match_ip_next_hop_type_cmd); |
2042 | route_map_install_match(&route_match_ipv6_next_hop_type_cmd); | |
d62a17ae | 2043 | route_map_install_match(&route_match_source_protocol_cmd); |
633a66a5 DS |
2044 | route_map_install_match(&route_match_source_instance_cmd); |
2045 | ||
d62a17ae | 2046 | /* */ |
2047 | route_map_install_set(&route_set_src_cmd); | |
2048 | /* */ | |
2049 | install_element(RMAP_NODE, &match_ip_nexthop_prefix_len_cmd); | |
2050 | install_element(RMAP_NODE, &no_match_ip_nexthop_prefix_len_cmd); | |
2051 | install_element(RMAP_NODE, &match_ip_address_prefix_len_cmd); | |
5165d46f DS |
2052 | install_element(RMAP_NODE, &match_ipv6_address_prefix_len_cmd); |
2053 | install_element(RMAP_NODE, &no_match_ipv6_address_prefix_len_cmd); | |
d62a17ae | 2054 | install_element(RMAP_NODE, &no_match_ip_address_prefix_len_cmd); |
2055 | install_element(RMAP_NODE, &match_source_protocol_cmd); | |
2056 | install_element(RMAP_NODE, &no_match_source_protocol_cmd); | |
633a66a5 DS |
2057 | install_element(RMAP_NODE, &match_source_instance_cmd); |
2058 | install_element(RMAP_NODE, &no_match_source_instance_cmd); | |
2059 | ||
d62a17ae | 2060 | /* */ |
2061 | install_element(RMAP_NODE, &set_src_cmd); | |
2062 | install_element(RMAP_NODE, &no_set_src_cmd); | |
5921ef9a | 2063 | } |