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