]> git.proxmox.com Git - mirror_frr.git/blame - lib/filter_nb.c
lib: fix access list mac removal command
[mirror_frr.git] / lib / filter_nb.c
CommitLineData
4470143b
RZ
1/*
2 * FRR filter northbound implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23#include "zebra.h"
24
4470143b
RZ
25#include "lib/northbound.h"
26#include "lib/prefix.h"
27
28#include "lib/filter.h"
29#include "lib/plist.h"
30#include "lib/plist_int.h"
31
fb8884f3
RZ
32/* Helper function. */
33static in_addr_t
34ipv4_network_addr(in_addr_t hostaddr, int masklen)
35{
36 struct in_addr mask;
37
38 masklen2ip(masklen, &mask);
39 return hostaddr & mask.s_addr;
40}
41
4362a768
RZ
42static enum nb_error
43prefix_list_length_validate(const struct lyd_node *dnode)
44{
45 int type = yang_dnode_get_enum(dnode, "../../type");
46 const char *xpath_le = NULL, *xpath_ge = NULL;
47 struct prefix p;
48 uint8_t le, ge;
49
50 if (type == 0 /* ipv4 */) {
51 yang_dnode_get_prefix(&p, dnode, "../ipv4-prefix");
52 xpath_le = "../ipv4-prefix-length-lesser-or-equal";
53 xpath_ge = "../ipv4-prefix-length-greater-or-equal";
54 } else {
55 yang_dnode_get_prefix(&p, dnode, "../ipv6-prefix");
56 xpath_le = "../ipv6-prefix-length-lesser-or-equal";
57 xpath_ge = "../ipv6-prefix-length-greater-or-equal";
58 }
59
60 /*
61 * Check rule:
62 * prefix length <= le.
63 */
64 if (yang_dnode_exists(dnode, xpath_le)) {
65 le = yang_dnode_get_uint8(dnode, xpath_le);
66 if (p.prefixlen > le)
67 goto log_and_fail;
68
69 }
70
71 /*
72 * Check rule:
73 * prefix length < ge.
74 */
75 if (yang_dnode_exists(dnode, xpath_ge)) {
76 ge = yang_dnode_get_uint8(dnode, xpath_ge);
77 if (p.prefixlen >= ge)
78 goto log_and_fail;
79 }
80
81 /*
82 * Check rule:
83 * ge <= le.
84 */
85 if (yang_dnode_exists(dnode, xpath_le) &&
86 yang_dnode_exists(dnode, xpath_ge)) {
87 le = yang_dnode_get_uint8(dnode, xpath_le);
88 ge = yang_dnode_get_uint8(dnode, xpath_ge);
89 if (ge > le)
90 goto log_and_fail;
91 }
92
93 return NB_OK;
94
95 log_and_fail:
96 zlog_info("prefix-list: invalid prefix range for %pFX: "
97 "Make sure that mask length < ge <= le", &p);
98 return NB_ERR_VALIDATION;
99}
100
4470143b
RZ
101/*
102 * XPath: /frr-filter:lib/access-list-legacy
103 */
fb8884f3 104static int lib_access_list_legacy_create(struct nb_cb_create_args *args)
4470143b
RZ
105{
106 struct access_list *acl;
107 const char *acl_name;
108
fb8884f3 109 if (args->event != NB_EV_APPLY)
4470143b
RZ
110 return NB_OK;
111
fb8884f3 112 acl_name = yang_dnode_get_string(args->dnode, "./number");
4470143b 113 acl = access_list_get(AFI_IP, acl_name);
fb8884f3 114 nb_running_set_entry(args->dnode, acl);
4470143b
RZ
115
116 return NB_OK;
117}
118
fb8884f3 119static int lib_access_list_legacy_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
120{
121 struct access_master *am;
122 struct access_list *acl;
123
fb8884f3 124 if (args->event != NB_EV_APPLY)
4470143b
RZ
125 return NB_OK;
126
fb8884f3 127 acl = nb_running_unset_entry(args->dnode);
4470143b
RZ
128 am = acl->master;
129 if (am->delete_hook)
130 am->delete_hook(acl);
131
132 access_list_delete(acl);
133
134 return NB_OK;
135}
136
137/*
138 * XPath: /frr-filter:lib/access-list-legacy/remark
139 */
fb8884f3 140static int lib_access_list_legacy_remark_modify(struct nb_cb_modify_args *args)
4470143b
RZ
141{
142 struct access_list *acl;
143 const char *remark;
144
fb8884f3 145 if (args->event != NB_EV_APPLY)
4470143b
RZ
146 return NB_OK;
147
fb8884f3 148 acl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
149 if (acl->remark)
150 XFREE(MTYPE_TMP, acl->remark);
151
fb8884f3 152 remark = yang_dnode_get_string(args->dnode, NULL);
4470143b
RZ
153 acl->remark = XSTRDUP(MTYPE_TMP, remark);
154
155 return NB_OK;
156}
157
fb8884f3
RZ
158static int
159lib_access_list_legacy_remark_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
160{
161 struct access_list *acl;
162
fb8884f3 163 if (args->event != NB_EV_APPLY)
4470143b
RZ
164 return NB_OK;
165
fb8884f3 166 acl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
167 if (acl->remark)
168 XFREE(MTYPE_TMP, acl->remark);
169
170 acl->remark = NULL;
171
172 return NB_OK;
173}
174
175/*
176 * XPath: /frr-filter:lib/access-list-legacy/entry
177 */
fb8884f3 178static int lib_access_list_legacy_entry_create(struct nb_cb_create_args *args)
4470143b
RZ
179{
180 struct filter_cisco *fc;
181 struct access_list *acl;
182 struct filter *f;
183 uint32_t aclno;
184
185 /* TODO: validate `filter_lookup_cisco` returns NULL. */
186
fb8884f3 187 if (args->event != NB_EV_APPLY)
4470143b
RZ
188 return NB_OK;
189
fb8884f3 190 aclno = yang_dnode_get_uint16(args->dnode, "../number");
4470143b
RZ
191
192 f = filter_new();
193 f->cisco = 1;
fb8884f3 194 f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
4470143b
RZ
195 fc = &f->u.cfilter;
196 if ((aclno >= 1 && aclno <= 99) || (aclno >= 1300 && aclno <= 1999))
197 fc->extended = 0;
198 else
199 fc->extended = 1;
200
fb8884f3 201 acl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
202 f->acl = acl;
203 access_list_filter_add(acl, f);
fb8884f3 204 nb_running_set_entry(args->dnode, f);
4470143b
RZ
205
206 return NB_OK;
207}
208
fb8884f3 209static int lib_access_list_legacy_entry_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
210{
211 struct access_list *acl;
212 struct filter *f;
213
fb8884f3 214 if (args->event != NB_EV_APPLY)
4470143b
RZ
215 return NB_OK;
216
fb8884f3 217 f = nb_running_unset_entry(args->dnode);
4470143b
RZ
218 acl = f->acl;
219 access_list_filter_delete(acl, f);
220
221 return NB_OK;
222}
223
224/*
225 * XPath: /frr-filter:lib/access-list-legacy/entry/action
226 */
227static int
fb8884f3 228lib_access_list_legacy_entry_action_modify(struct nb_cb_modify_args *args)
4470143b
RZ
229{
230 const char *filter_type;
231 struct filter *f;
232
fb8884f3 233 if (args->event != NB_EV_APPLY)
4470143b
RZ
234 return NB_OK;
235
fb8884f3
RZ
236 f = nb_running_get_entry(args->dnode, NULL, true);
237 filter_type = yang_dnode_get_string(args->dnode, NULL);
4470143b
RZ
238 if (strcmp(filter_type, "permit") == 0)
239 f->type = FILTER_PERMIT;
240 else
241 f->type = FILTER_DENY;
242
243 return NB_OK;
244}
245
246/*
247 * XPath: /frr-filter:lib/access-list-legacy/entry/host
248 */
249static int
fb8884f3 250lib_access_list_legacy_entry_host_modify(struct nb_cb_modify_args *args)
4470143b
RZ
251{
252 struct filter_cisco *fc;
253 struct filter *f;
254
fb8884f3 255 if (args->event != NB_EV_APPLY)
4470143b
RZ
256 return NB_OK;
257
fb8884f3 258 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 259 fc = &f->u.cfilter;
fb8884f3 260 yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
4470143b
RZ
261 fc->addr_mask.s_addr = INADDR_ANY;
262
263 return NB_OK;
264}
265
266static int
fb8884f3 267lib_access_list_legacy_entry_host_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
268{
269 struct filter_cisco *fc;
270 struct filter *f;
271
fb8884f3 272 if (args->event != NB_EV_APPLY)
4470143b
RZ
273 return NB_OK;
274
fb8884f3 275 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
276 fc = &f->u.cfilter;
277 fc->addr.s_addr = INADDR_ANY;
278 fc->addr_mask.s_addr = INADDR_NONE;
279
280 return NB_OK;
281}
282
283/*
284 * XPath: /frr-filter:lib/access-list-legacy/entry/network
285 */
286static int
fb8884f3 287lib_access_list_legacy_entry_network_modify(struct nb_cb_modify_args *args)
4470143b
RZ
288{
289 struct filter_cisco *fc;
290 struct filter *f;
291 struct prefix p;
292
fb8884f3 293 if (args->event != NB_EV_APPLY)
4470143b
RZ
294 return NB_OK;
295
fb8884f3 296 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 297 fc = &f->u.cfilter;
fb8884f3 298 yang_dnode_get_prefix(&p, args->dnode, NULL);
4470143b
RZ
299 fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
300 masklen2ip(p.prefixlen, &fc->addr_mask);
301
302 return NB_OK;
303}
304
305static int
fb8884f3 306lib_access_list_legacy_entry_network_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
307{
308 struct filter_cisco *fc;
309 struct filter *f;
310
fb8884f3 311 if (args->event != NB_EV_APPLY)
4470143b
RZ
312 return NB_OK;
313
fb8884f3 314 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
315 fc = &f->u.cfilter;
316 fc->addr.s_addr = INADDR_ANY;
317 fc->addr_mask.s_addr = INADDR_NONE;
318
319 return NB_OK;
320}
321
322/*
323 * XPath: /frr-filter:lib/access-list-legacy/entry/any
324 */
fb8884f3
RZ
325static int
326lib_access_list_legacy_entry_any_create(struct nb_cb_create_args *args)
4470143b
RZ
327{
328 struct filter_cisco *fc;
329 struct filter *f;
330
fb8884f3 331 if (args->event != NB_EV_APPLY)
4470143b
RZ
332 return NB_OK;
333
fb8884f3 334 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
335 fc = &f->u.cfilter;
336 fc->addr.s_addr = INADDR_ANY;
337 fc->addr_mask.s_addr = INADDR_NONE;
338
339 return NB_OK;
340}
341
342static int
fb8884f3 343lib_access_list_legacy_entry_any_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
344{
345 struct filter_cisco *fc;
346 struct filter *f;
347
fb8884f3 348 if (args->event != NB_EV_APPLY)
4470143b
RZ
349 return NB_OK;
350
fb8884f3 351 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
352 fc = &f->u.cfilter;
353 fc->addr.s_addr = INADDR_ANY;
354 fc->addr_mask.s_addr = INADDR_NONE;
355
356 return NB_OK;
357}
358
359/*
360 * XPath: /frr-filter:lib/access-list-legacy/entry/destination-host
361 */
362static int lib_access_list_legacy_entry_destination_host_modify(
fb8884f3 363 struct nb_cb_modify_args *args)
4470143b
RZ
364{
365 struct filter_cisco *fc;
366 struct filter *f;
367
fb8884f3 368 if (args->event != NB_EV_APPLY)
4470143b
RZ
369 return NB_OK;
370
fb8884f3 371 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 372 fc = &f->u.cfilter;
fb8884f3 373 yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
4470143b
RZ
374 fc->mask_mask.s_addr = INADDR_ANY;
375
376 return NB_OK;
377}
378
379static int lib_access_list_legacy_entry_destination_host_destroy(
fb8884f3 380 struct nb_cb_destroy_args *args)
4470143b
RZ
381{
382 struct filter_cisco *fc;
383 struct filter *f;
384
fb8884f3 385 if (args->event != NB_EV_APPLY)
4470143b
RZ
386 return NB_OK;
387
fb8884f3 388 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
389 fc = &f->u.cfilter;
390 fc->mask.s_addr = INADDR_ANY;
391 fc->mask_mask.s_addr = INADDR_NONE;
392
393 return NB_OK;
394}
395
396/*
397 * XPath: /frr-filter:lib/access-list-legacy/entry/destination-network
398 */
399static int lib_access_list_legacy_entry_destination_network_modify(
fb8884f3 400 struct nb_cb_modify_args *args)
4470143b
RZ
401{
402 struct filter_cisco *fc;
403 struct filter *f;
404 struct prefix p;
405
fb8884f3 406 if (args->event != NB_EV_APPLY)
4470143b
RZ
407 return NB_OK;
408
fb8884f3 409 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 410 fc = &f->u.cfilter;
fb8884f3 411 yang_dnode_get_prefix(&p, args->dnode, NULL);
4470143b
RZ
412 fc->addr.s_addr = ipv4_network_addr(p.u.prefix4.s_addr, p.prefixlen);
413 masklen2ip(p.prefixlen, &fc->addr_mask);
414
415 return NB_OK;
416}
417
418static int lib_access_list_legacy_entry_destination_network_destroy(
fb8884f3 419 struct nb_cb_destroy_args *args)
4470143b
RZ
420{
421 struct filter_cisco *fc;
422 struct filter *f;
423
fb8884f3 424 if (args->event != NB_EV_APPLY)
4470143b
RZ
425 return NB_OK;
426
fb8884f3 427 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
428 fc = &f->u.cfilter;
429 fc->mask.s_addr = INADDR_ANY;
430 fc->mask_mask.s_addr = INADDR_NONE;
431
432 return NB_OK;
433}
434
435/*
436 * XPath: /frr-filter:lib/access-list-legacy/entry/destination-any
437 */
438static int lib_access_list_legacy_entry_destination_any_create(
fb8884f3 439 struct nb_cb_create_args *args)
4470143b
RZ
440{
441 struct filter_cisco *fc;
442 struct filter *f;
443
fb8884f3 444 if (args->event != NB_EV_APPLY)
4470143b
RZ
445 return NB_OK;
446
fb8884f3 447 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
448 fc = &f->u.cfilter;
449 fc->mask.s_addr = INADDR_ANY;
450 fc->mask_mask.s_addr = INADDR_NONE;
451
452 return NB_OK;
453}
454
455static int lib_access_list_legacy_entry_destination_any_destroy(
fb8884f3 456 struct nb_cb_destroy_args *args)
4470143b
RZ
457{
458 struct filter_cisco *fc;
459 struct filter *f;
460
fb8884f3 461 if (args->event != NB_EV_APPLY)
4470143b
RZ
462 return NB_OK;
463
fb8884f3 464 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
465 fc = &f->u.cfilter;
466 fc->mask.s_addr = INADDR_ANY;
467 fc->mask_mask.s_addr = INADDR_NONE;
468
469 return NB_OK;
470}
471
472/*
473 * XPath: /frr-filter:lib/access-list
474 */
fb8884f3 475static int lib_access_list_create(struct nb_cb_create_args *args)
4470143b 476{
ff94358e 477 struct access_list *acl = NULL;
4470143b
RZ
478 const char *acl_name;
479 int type;
480
fb8884f3 481 if (args->event != NB_EV_APPLY)
4470143b
RZ
482 return NB_OK;
483
fb8884f3
RZ
484 type = yang_dnode_get_enum(args->dnode, "./type");
485 acl_name = yang_dnode_get_string(args->dnode, "./name");
4470143b
RZ
486
487 switch (type) {
488 case 0: /* ipv4 */
489 acl = access_list_get(AFI_IP, acl_name);
490 break;
491 case 1: /* ipv6 */
492 acl = access_list_get(AFI_IP6, acl_name);
493 break;
494 case 2: /* mac */
495 acl = access_list_get(AFI_L2VPN, acl_name);
496 break;
497 }
498
fb8884f3 499 nb_running_set_entry(args->dnode, acl);
4470143b
RZ
500
501 return NB_OK;
502}
503
fb8884f3 504static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
505{
506 struct access_master *am;
507 struct access_list *acl;
508
fb8884f3 509 if (args->event != NB_EV_APPLY)
4470143b
RZ
510 return NB_OK;
511
fb8884f3 512 acl = nb_running_unset_entry(args->dnode);
4470143b
RZ
513 am = acl->master;
514 if (am->delete_hook)
515 am->delete_hook(acl);
516
517 access_list_delete(acl);
518
519 return NB_OK;
520}
521
522/*
523 * XPath: /frr-filter:lib/access-list/remark
524 */
fb8884f3 525static int lib_access_list_remark_modify(struct nb_cb_modify_args *args)
4470143b 526{
fb8884f3 527 return lib_access_list_legacy_remark_modify(args);
4470143b
RZ
528}
529
fb8884f3 530static int lib_access_list_remark_destroy(struct nb_cb_destroy_args *args)
4470143b 531{
fb8884f3 532 return lib_access_list_legacy_remark_destroy(args);
4470143b
RZ
533}
534
535/*
536 * XPath: /frr-filter:lib/access-list/entry
537 */
fb8884f3 538static int lib_access_list_entry_create(struct nb_cb_create_args *args)
4470143b
RZ
539{
540 struct access_list *acl;
541 struct filter *f;
542
543 /* TODO: validate `filter_lookup_zebra` returns NULL. */
544
fb8884f3 545 if (args->event != NB_EV_APPLY)
4470143b
RZ
546 return NB_OK;
547
548 f = filter_new();
fb8884f3 549 f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
4470143b 550
fb8884f3 551 acl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
552 f->acl = acl;
553 access_list_filter_add(acl, f);
fb8884f3 554 nb_running_set_entry(args->dnode, f);
4470143b
RZ
555
556 return NB_OK;
557}
558
fb8884f3 559static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
560{
561 struct access_list *acl;
562 struct filter *f;
563
fb8884f3 564 if (args->event != NB_EV_APPLY)
4470143b
RZ
565 return NB_OK;
566
fb8884f3 567 f = nb_running_unset_entry(args->dnode);
4470143b
RZ
568 acl = f->acl;
569 access_list_filter_delete(acl, f);
570
571 return NB_OK;
572}
573
574/*
575 * XPath: /frr-filter:lib/access-list/entry/action
576 */
fb8884f3 577static int lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
4470143b 578{
fb8884f3 579 return lib_access_list_legacy_entry_action_modify(args);
4470143b
RZ
580}
581
582/*
583 * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
584 */
585static int
fb8884f3 586lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
4470143b
RZ
587{
588 struct filter_zebra *fz;
589 struct filter *f;
590
fb8884f3 591 if (args->event != NB_EV_APPLY)
4470143b
RZ
592 return NB_OK;
593
fb8884f3 594 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 595 fz = &f->u.zfilter;
fb8884f3 596 yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
4470143b
RZ
597
598 return NB_OK;
599}
600
601static int
fb8884f3 602lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
603{
604 struct filter_zebra *fz;
605 struct filter *f;
606
fb8884f3 607 if (args->event != NB_EV_APPLY)
4470143b
RZ
608 return NB_OK;
609
fb8884f3 610 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
611 fz = &f->u.zfilter;
612 memset(&fz->prefix, 0, sizeof(fz->prefix));
613
614 return NB_OK;
615}
616
617/*
618 * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
619 */
620static int
fb8884f3 621lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
4470143b
RZ
622{
623 struct filter_zebra *fz;
624 struct filter *f;
625
fb8884f3 626 if (args->event != NB_EV_APPLY)
4470143b
RZ
627 return NB_OK;
628
fb8884f3 629 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b 630 fz = &f->u.zfilter;
fb8884f3 631 fz->exact = yang_dnode_get_bool(args->dnode, NULL);
4470143b
RZ
632
633 return NB_OK;
634}
635
636static int
fb8884f3 637lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
638{
639 struct filter_zebra *fz;
640 struct filter *f;
641
fb8884f3 642 if (args->event != NB_EV_APPLY)
4470143b
RZ
643 return NB_OK;
644
fb8884f3 645 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
646 fz = &f->u.zfilter;
647 fz->exact = 0;
648
649 return NB_OK;
650}
651
652/*
653 * XPath: /frr-filter:lib/access-list/entry/ipv6-prefix
654 */
655static int
fb8884f3 656lib_access_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
4470143b 657{
fb8884f3 658 return lib_access_list_entry_ipv4_prefix_modify(args);
4470143b
RZ
659}
660
661static int
fb8884f3 662lib_access_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
4470143b 663{
fb8884f3 664 return lib_access_list_entry_ipv4_prefix_destroy(args);
4470143b
RZ
665}
666
667/*
668 * XPath: /frr-filter:lib/access-list/entry/ipv6-exact-match
669 */
670static int
fb8884f3 671lib_access_list_entry_ipv6_exact_match_modify(struct nb_cb_modify_args *args)
4470143b 672{
fb8884f3 673 return lib_access_list_entry_ipv4_exact_match_modify(args);
4470143b
RZ
674}
675
676static int
fb8884f3 677lib_access_list_entry_ipv6_exact_match_destroy(struct nb_cb_destroy_args *args)
4470143b 678{
fb8884f3 679 return lib_access_list_entry_ipv4_exact_match_destroy(args);
4470143b
RZ
680}
681
682/*
683 * XPath: /frr-filter:lib/access-list/entry/mac
684 */
fb8884f3 685static int lib_access_list_entry_mac_modify(struct nb_cb_modify_args *args)
4470143b 686{
fb8884f3 687 return lib_access_list_entry_ipv4_prefix_modify(args);
4470143b
RZ
688}
689
fb8884f3 690static int lib_access_list_entry_mac_destroy(struct nb_cb_destroy_args *args)
4470143b 691{
fb8884f3 692 return lib_access_list_entry_ipv4_prefix_destroy(args);
4470143b
RZ
693}
694
695/*
696 * XPath: /frr-filter:lib/access-list/entry/any
697 */
fb8884f3 698static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
4470143b
RZ
699{
700 struct filter_zebra *fz;
701 struct filter *f;
702 int type;
703
fb8884f3 704 if (args->event != NB_EV_APPLY)
4470143b
RZ
705 return NB_OK;
706
fb8884f3 707 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
708 fz = &f->u.zfilter;
709 memset(&fz->prefix, 0, sizeof(fz->prefix));
710
fb8884f3 711 type = yang_dnode_get_enum(args->dnode, "../../type");
4470143b
RZ
712 switch (type) {
713 case 0: /* ipv4 */
714 fz->prefix.family = AF_INET;
715 break;
716 case 1: /* ipv6 */
717 fz->prefix.family = AF_INET6;
718 break;
719 case 2: /* mac */
720 fz->prefix.family = AF_ETHERNET;
721 break;
722 }
723
724 return NB_OK;
725}
726
fb8884f3 727static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
728{
729 struct filter_zebra *fz;
730 struct filter *f;
731
fb8884f3 732 if (args->event != NB_EV_APPLY)
4470143b
RZ
733 return NB_OK;
734
fb8884f3 735 f = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
736 fz = &f->u.zfilter;
737 fz->prefix.family = 0;
738
739 return NB_OK;
740}
741
742/*
743 * XPath: /frr-filter:lib/prefix-list
744 */
fb8884f3 745static int lib_prefix_list_create(struct nb_cb_create_args *args)
4470143b 746{
ff94358e 747 struct prefix_list *pl = NULL;
4470143b
RZ
748 const char *name;
749 int type;
750
751 /* TODO: validate prefix_entry_dup_check() passes. */
752
fb8884f3 753 if (args->event != NB_EV_APPLY)
4470143b
RZ
754 return NB_OK;
755
fb8884f3
RZ
756 type = yang_dnode_get_enum(args->dnode, "./type");
757 name = yang_dnode_get_string(args->dnode, "./name");
4470143b
RZ
758 switch (type) {
759 case 0: /* ipv4 */
760 pl = prefix_list_get(AFI_IP, 0, name);
761 break;
762 case 1: /* ipv6 */
763 pl = prefix_list_get(AFI_IP6, 0, name);
764 break;
765 }
766
fb8884f3 767 nb_running_set_entry(args->dnode, pl);
4470143b
RZ
768
769 return NB_OK;
770}
771
fb8884f3 772static int lib_prefix_list_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
773{
774 struct prefix_list *pl;
775
fb8884f3 776 if (args->event != NB_EV_APPLY)
4470143b
RZ
777 return NB_OK;
778
fb8884f3 779 pl = nb_running_unset_entry(args->dnode);
4470143b
RZ
780 prefix_list_delete(pl);
781
782 return NB_OK;
783}
784
785/*
cc82bcc1 786 * XPath: /frr-filter:lib/prefix-list/remark
4470143b 787 */
cc82bcc1 788static int lib_prefix_list_remark_modify(struct nb_cb_modify_args *args)
4470143b
RZ
789{
790 struct prefix_list *pl;
791 const char *remark;
792
fb8884f3 793 if (args->event != NB_EV_APPLY)
4470143b
RZ
794 return NB_OK;
795
fb8884f3 796 pl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
797 if (pl->desc)
798 XFREE(MTYPE_TMP, pl->desc);
799
fb8884f3 800 remark = yang_dnode_get_string(args->dnode, NULL);
4470143b
RZ
801 pl->desc = XSTRDUP(MTYPE_TMP, remark);
802
803 return NB_OK;
804}
805
cc82bcc1 806static int lib_prefix_list_remark_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
807{
808 struct prefix_list *pl;
809
fb8884f3 810 if (args->event != NB_EV_APPLY)
4470143b
RZ
811 return NB_OK;
812
fb8884f3 813 pl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
814 if (pl->desc)
815 XFREE(MTYPE_TMP, pl->desc);
816
817 pl->desc = NULL;
818
819 return NB_OK;
820}
821
822/*
823 * XPath: /frr-filter:lib/prefix-list/entry
824 */
fb8884f3 825static int lib_prefix_list_entry_create(struct nb_cb_create_args *args)
4470143b
RZ
826{
827 struct prefix_list_entry *ple;
828 struct prefix_list *pl;
829 struct prefix p;
830
fb8884f3 831 if (args->event != NB_EV_APPLY)
4470143b
RZ
832 return NB_OK;
833
834 memset(&p, 0, sizeof(p));
835
fb8884f3 836 pl = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
837 ple = prefix_list_entry_new();
838 ple->pl = pl;
839 ple->any = 1;
cc82bcc1 840 ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
4470143b
RZ
841
842 return NB_OK;
843}
844
fb8884f3 845static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
846{
847 struct prefix_list_entry *ple;
848
fb8884f3 849 if (args->event != NB_EV_APPLY)
4470143b
RZ
850 return NB_OK;
851
fb8884f3 852 ple = nb_running_unset_entry(args->dnode);
4470143b
RZ
853 prefix_list_entry_delete(ple->pl, ple, 1);
854
855 return NB_OK;
856}
857
858/*
859 * XPath: /frr-filter:lib/prefix-list/entry/action
860 */
fb8884f3 861static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
4470143b
RZ
862{
863 struct prefix_list_entry *ple;
864 const char *action_str;
865
fb8884f3 866 if (args->event != NB_EV_APPLY)
4470143b
RZ
867 return NB_OK;
868
fb8884f3 869 ple = nb_running_get_entry(args->dnode, NULL, true);
cc82bcc1 870 action_str = yang_dnode_get_string(args->dnode, NULL);
4470143b
RZ
871 if (strcmp(action_str, "permit") == 0)
872 ple->type = PREFIX_PERMIT;
873 else
874 ple->type = PREFIX_DENY;
875
876 return NB_OK;
877}
878
879/*
880 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
881 */
882static int
fb8884f3 883lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
4470143b
RZ
884{
885 struct prefix_list_entry *ple;
886
fb8884f3 887 if (args->event != NB_EV_APPLY)
4470143b
RZ
888 return NB_OK;
889
fb8884f3
RZ
890 ple = nb_running_get_entry(args->dnode, NULL, true);
891 yang_dnode_get_prefix(&ple->prefix, args->dnode, NULL);
4470143b
RZ
892
893 return NB_OK;
894}
895
896static int
fb8884f3 897lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
898{
899 struct prefix_list_entry *ple;
900
fb8884f3 901 if (args->event != NB_EV_APPLY)
4470143b
RZ
902 return NB_OK;
903
fb8884f3 904 ple = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
905 memset(&ple->prefix, 0, sizeof(ple->prefix));
906 ple->any = 1;
907
908 return NB_OK;
909}
910
911/*
912 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
913 */
914static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
fb8884f3 915 struct nb_cb_modify_args *args)
4470143b
RZ
916{
917 struct prefix_list_entry *ple;
918
4362a768
RZ
919 if (args->event == NB_EV_VALIDATE &&
920 prefix_list_length_validate(args->dnode) != NB_OK)
921 return NB_ERR_VALIDATION;
922
fb8884f3 923 if (args->event != NB_EV_APPLY)
4470143b
RZ
924 return NB_OK;
925
fb8884f3
RZ
926 ple = nb_running_get_entry(args->dnode, NULL, true);
927 ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
4470143b
RZ
928
929 return NB_OK;
930}
931
932static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
fb8884f3 933 struct nb_cb_destroy_args *args)
4470143b
RZ
934{
935 struct prefix_list_entry *ple;
936
fb8884f3 937 if (args->event != NB_EV_APPLY)
4470143b
RZ
938 return NB_OK;
939
fb8884f3 940 ple = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
941 ple->ge = 0;
942
943 return NB_OK;
944}
945
946/*
947 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
948 */
949static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
fb8884f3 950 struct nb_cb_modify_args *args)
4470143b
RZ
951{
952 struct prefix_list_entry *ple;
953
4362a768
RZ
954 if (args->event == NB_EV_VALIDATE &&
955 prefix_list_length_validate(args->dnode) != NB_OK)
956 return NB_ERR_VALIDATION;
957
fb8884f3 958 if (args->event != NB_EV_APPLY)
4470143b
RZ
959 return NB_OK;
960
fb8884f3
RZ
961 ple = nb_running_get_entry(args->dnode, NULL, true);
962 ple->le = yang_dnode_get_uint8(args->dnode, NULL);
4470143b
RZ
963
964 return NB_OK;
965}
966
967static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
fb8884f3 968 struct nb_cb_destroy_args *args)
4470143b
RZ
969{
970 struct prefix_list_entry *ple;
971
fb8884f3 972 if (args->event != NB_EV_APPLY)
4470143b
RZ
973 return NB_OK;
974
fb8884f3 975 ple = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
976 ple->le = 0;
977
978 return NB_OK;
979}
980
981/*
982 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix
983 */
984static int
fb8884f3 985lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
4470143b 986{
fb8884f3 987 return lib_prefix_list_entry_ipv4_prefix_modify(args);
4470143b
RZ
988}
989
990static int
fb8884f3 991lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
4470143b 992{
fb8884f3 993 return lib_prefix_list_entry_ipv4_prefix_destroy(args);
4470143b
RZ
994}
995
996/*
997 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal
998 */
999static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
fb8884f3 1000 struct nb_cb_modify_args *args)
4470143b
RZ
1001{
1002 return lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
fb8884f3 1003 args);
4470143b
RZ
1004}
1005
1006static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy(
fb8884f3 1007 struct nb_cb_destroy_args *args)
4470143b
RZ
1008{
1009 return lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
fb8884f3 1010 args);
4470143b
RZ
1011}
1012
1013/*
1014 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal
1015 */
1016static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify(
fb8884f3 1017 struct nb_cb_modify_args *args)
4470143b
RZ
1018{
1019 return lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
fb8884f3 1020 args);
4470143b
RZ
1021}
1022
1023static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy(
fb8884f3 1024 struct nb_cb_destroy_args *args)
4470143b
RZ
1025{
1026 return lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
fb8884f3 1027 args);
4470143b
RZ
1028}
1029
1030/*
1031 * XPath: /frr-filter:lib/prefix-list/entry/any
1032 */
fb8884f3 1033static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
4470143b
RZ
1034{
1035 struct prefix_list_entry *ple;
1036
fb8884f3 1037 if (args->event != NB_EV_APPLY)
4470143b
RZ
1038 return NB_OK;
1039
fb8884f3 1040 ple = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
1041 memset(&ple->prefix, 0, sizeof(ple->prefix));
1042 ple->any = 1;
1043
1044 return NB_OK;
1045}
1046
fb8884f3 1047static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
4470143b
RZ
1048{
1049 struct prefix_list_entry *ple;
1050
fb8884f3 1051 if (args->event != NB_EV_APPLY)
4470143b
RZ
1052 return NB_OK;
1053
fb8884f3 1054 ple = nb_running_get_entry(args->dnode, NULL, true);
4470143b
RZ
1055 memset(&ple->prefix, 0, sizeof(ple->prefix));
1056 ple->any = 1;
1057
1058 return NB_OK;
1059}
1060
1061/* clang-format off */
1062const struct frr_yang_module_info frr_filter_info = {
1063 .name = "frr-filter",
1064 .nodes = {
1065 {
1066 .xpath = "/frr-filter:lib/access-list-legacy",
1067 .cbs = {
1068 .create = lib_access_list_legacy_create,
1069 .destroy = lib_access_list_legacy_destroy,
1070 }
1071 },
1072 {
1073 .xpath = "/frr-filter:lib/access-list-legacy/remark",
1074 .cbs = {
1075 .modify = lib_access_list_legacy_remark_modify,
1076 .destroy = lib_access_list_legacy_remark_destroy,
1d3c4b66 1077 .cli_show = access_list_legacy_remark_show,
4470143b
RZ
1078 }
1079 },
1080 {
1081 .xpath = "/frr-filter:lib/access-list-legacy/entry",
1082 .cbs = {
1083 .create = lib_access_list_legacy_entry_create,
1084 .destroy = lib_access_list_legacy_entry_destroy,
1d3c4b66 1085 .cli_show = access_list_legacy_show,
4470143b
RZ
1086 }
1087 },
1088 {
1089 .xpath = "/frr-filter:lib/access-list-legacy/entry/action",
1090 .cbs = {
1091 .modify = lib_access_list_legacy_entry_action_modify,
1092 }
1093 },
1094 {
1095 .xpath = "/frr-filter:lib/access-list-legacy/entry/host",
1096 .cbs = {
1097 .modify = lib_access_list_legacy_entry_host_modify,
1098 .destroy = lib_access_list_legacy_entry_host_destroy,
1099 }
1100 },
1101 {
1102 .xpath = "/frr-filter:lib/access-list-legacy/entry/network",
1103 .cbs = {
1104 .modify = lib_access_list_legacy_entry_network_modify,
1105 .destroy = lib_access_list_legacy_entry_network_destroy,
1106 }
1107 },
1108 {
1109 .xpath = "/frr-filter:lib/access-list-legacy/entry/any",
1110 .cbs = {
1111 .create = lib_access_list_legacy_entry_any_create,
1112 .destroy = lib_access_list_legacy_entry_any_destroy,
1113 }
1114 },
1115 {
1116 .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-host",
1117 .cbs = {
1118 .modify = lib_access_list_legacy_entry_destination_host_modify,
1119 .destroy = lib_access_list_legacy_entry_destination_host_destroy,
1120 }
1121 },
1122 {
1123 .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-network",
1124 .cbs = {
1125 .modify = lib_access_list_legacy_entry_destination_network_modify,
1126 .destroy = lib_access_list_legacy_entry_destination_network_destroy,
1127 }
1128 },
1129 {
1130 .xpath = "/frr-filter:lib/access-list-legacy/entry/destination-any",
1131 .cbs = {
1132 .create = lib_access_list_legacy_entry_destination_any_create,
1133 .destroy = lib_access_list_legacy_entry_destination_any_destroy,
1134 }
1135 },
1136 {
1137 .xpath = "/frr-filter:lib/access-list",
1138 .cbs = {
1139 .create = lib_access_list_create,
1140 .destroy = lib_access_list_destroy,
1141 }
1142 },
1143 {
1144 .xpath = "/frr-filter:lib/access-list/remark",
1145 .cbs = {
1146 .modify = lib_access_list_remark_modify,
1147 .destroy = lib_access_list_remark_destroy,
1d3c4b66 1148 .cli_show = access_list_remark_show,
4470143b
RZ
1149 }
1150 },
1151 {
1152 .xpath = "/frr-filter:lib/access-list/entry",
1153 .cbs = {
1154 .create = lib_access_list_entry_create,
1155 .destroy = lib_access_list_entry_destroy,
1d3c4b66 1156 .cli_show = access_list_show,
4470143b
RZ
1157 }
1158 },
1159 {
1160 .xpath = "/frr-filter:lib/access-list/entry/action",
1161 .cbs = {
1162 .modify = lib_access_list_entry_action_modify,
1163 }
1164 },
1165 {
1166 .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
1167 .cbs = {
1168 .modify = lib_access_list_entry_ipv4_prefix_modify,
1169 .destroy = lib_access_list_entry_ipv4_prefix_destroy,
1170 }
1171 },
1172 {
1173 .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
1174 .cbs = {
1175 .modify = lib_access_list_entry_ipv4_exact_match_modify,
1176 .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
1177 }
1178 },
1179 {
1180 .xpath = "/frr-filter:lib/access-list/entry/ipv6-prefix",
1181 .cbs = {
1182 .modify = lib_access_list_entry_ipv6_prefix_modify,
1183 .destroy = lib_access_list_entry_ipv6_prefix_destroy,
1184 }
1185 },
1186 {
1187 .xpath = "/frr-filter:lib/access-list/entry/ipv6-exact-match",
1188 .cbs = {
1189 .modify = lib_access_list_entry_ipv6_exact_match_modify,
1190 .destroy = lib_access_list_entry_ipv6_exact_match_destroy,
1191 }
1192 },
1193 {
1194 .xpath = "/frr-filter:lib/access-list/entry/mac",
1195 .cbs = {
1196 .modify = lib_access_list_entry_mac_modify,
1197 .destroy = lib_access_list_entry_mac_destroy,
1198 }
1199 },
1200 {
1201 .xpath = "/frr-filter:lib/access-list/entry/any",
1202 .cbs = {
1203 .create = lib_access_list_entry_any_create,
1204 .destroy = lib_access_list_entry_any_destroy,
1205 }
1206 },
1207 {
1208 .xpath = "/frr-filter:lib/prefix-list",
1209 .cbs = {
1210 .create = lib_prefix_list_create,
1211 .destroy = lib_prefix_list_destroy,
1212 }
1213 },
1214 {
cc82bcc1 1215 .xpath = "/frr-filter:lib/prefix-list/remark",
4470143b 1216 .cbs = {
cc82bcc1
RZ
1217 .modify = lib_prefix_list_remark_modify,
1218 .destroy = lib_prefix_list_remark_destroy,
1d3c4b66 1219 .cli_show = prefix_list_remark_show,
4470143b
RZ
1220 }
1221 },
1222 {
1223 .xpath = "/frr-filter:lib/prefix-list/entry",
1224 .cbs = {
1225 .create = lib_prefix_list_entry_create,
1226 .destroy = lib_prefix_list_entry_destroy,
1d3c4b66 1227 .cli_show = prefix_list_show,
4470143b
RZ
1228 }
1229 },
1230 {
1231 .xpath = "/frr-filter:lib/prefix-list/entry/action",
1232 .cbs = {
1233 .modify = lib_prefix_list_entry_action_modify,
1234 }
1235 },
1236 {
1237 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix",
1238 .cbs = {
1239 .modify = lib_prefix_list_entry_ipv4_prefix_modify,
1240 .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
1241 }
1242 },
1243 {
1244 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal",
1245 .cbs = {
1246 .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
1247 .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
1248 }
1249 },
1250 {
1251 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal",
1252 .cbs = {
1253 .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
1254 .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
1255 }
1256 },
1257 {
1258 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
1259 .cbs = {
1260 .modify = lib_prefix_list_entry_ipv6_prefix_modify,
1261 .destroy = lib_prefix_list_entry_ipv6_prefix_destroy,
1262 }
1263 },
1264 {
1265 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
1266 .cbs = {
1267 .modify = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify,
1268 .destroy = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy,
1269 }
1270 },
1271 {
1272 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
1273 .cbs = {
1274 .modify = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify,
1275 .destroy = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy,
1276 }
1277 },
1278 {
1279 .xpath = "/frr-filter:lib/prefix-list/entry/any",
1280 .cbs = {
1281 .create = lib_prefix_list_entry_any_create,
1282 .destroy = lib_prefix_list_entry_any_destroy,
1283 }
1284 },
1285 {
1286 .xpath = NULL,
1287 },
1288 }
1289};