diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 213834afc8f7..18e51e5eb6e1 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -120,6 +120,23 @@ void eigrp_cli_show_router_id(struct vty *vty, const struct lyd_node *dnode, vty_out(vty, " eigrp router-id %s\n", router_id); } +/* + * XPath: /frr-ripd:ripd/instance/passive-default + */ +DEFPY_YANG( + eigrp_passive_default, + eigrp_passive_default_cmd, + "[no] passive-interface default", + NO_STR + "Suppress routing updates on an interface\n" + "default for all interfaces\n") +{ + nb_cli_enqueue_change(vty, "./passive-default", NB_OP_MODIFY, + no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + /* * XPath: /frr-eigrpd:eigrpd/instance/passive-interface */ @@ -131,12 +148,19 @@ DEFPY_YANG( "Suppress routing updates on an interface\n" "Interface to suppress on\n") { - if (no) - nb_cli_enqueue_change(vty, "./passive-interface", - NB_OP_DESTROY, ifname); - else + bool passive_default = + yang_dnode_get_bool(vty->candidate_config->dnode, "%s%s", + VTY_CURR_XPATH, "/passive-default"); + + if (passive_default) { + nb_cli_enqueue_change(vty, "./non-passive-interface", + no ? NB_OP_CREATE : NB_OP_DESTROY, + ifname); + } else { nb_cli_enqueue_change(vty, "./passive-interface", - NB_OP_CREATE, ifname); + no ? NB_OP_DESTROY : NB_OP_CREATE, + ifname); + } return nb_cli_apply_changes(vty, NULL); } @@ -150,6 +174,15 @@ void eigrp_cli_show_passive_interface(struct vty *vty, vty_out(vty, " passive-interface %s\n", ifname); } +void eigrp_cli_show_non_passive_interface(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + const char *ifname = yang_dnode_get_string(dnode, NULL); + + vty_out(vty, "no passive-interface %s\n", ifname); +} + /* * XPath: /frr-eigrpd:eigrpd/instance/active-time */ @@ -826,6 +859,14 @@ void eigrp_cli_show_keychain(struct vty *vty, const struct lyd_node *dnode, keychain); } +void eigrpd_cli_show_passive_default(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " passive-interface default\n"); +} /* * CLI installation procedures. @@ -865,6 +906,7 @@ eigrp_cli_init(void) install_element(EIGRP_NODE, &eigrp_router_id_cmd); install_element(EIGRP_NODE, &no_eigrp_router_id_cmd); install_element(EIGRP_NODE, &eigrp_passive_interface_cmd); + install_element(EIGRP_NODE, &eigrp_passive_default_cmd); install_element(EIGRP_NODE, &eigrp_timers_active_cmd); install_element(EIGRP_NODE, &no_eigrp_timers_active_cmd); install_element(EIGRP_NODE, &eigrp_variance_cmd); diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h index ed7b27477b80..1242254f97f4 100644 --- a/eigrpd/eigrp_cli.h +++ b/eigrpd/eigrp_cli.h @@ -61,6 +61,12 @@ extern void eigrp_cli_show_authentication(struct vty *vty, extern void eigrp_cli_show_keychain(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void eigrpd_cli_show_passive_default(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +void eigrp_cli_show_non_passive_interface(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); extern void eigrp_cli_init(void); #endif /*EIGRP_CLI_H_ */ diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c index 4065459feaf3..96a4e46180bf 100644 --- a/eigrpd/eigrp_interface.c +++ b/eigrpd/eigrp_interface.c @@ -25,7 +25,7 @@ #include "network.h" #include "command.h" #include "stream.h" -#include "log.h" +#include "zlog.h" #include "keychain.h" #include "vrf.h" @@ -44,6 +44,9 @@ #include "eigrpd/eigrp_metric.h" DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF, "EIGRP interface"); +DEFINE_MTYPE_STATIC(EIGRPD, EIGRP_IF_STRING, "EIGRP Interface String"); + +static void eigrp_passive_interface_apply(struct interface *ifp); int eigrp_if_new_hook(struct interface *ifp) { @@ -114,6 +117,7 @@ static int eigrp_ifp_create(struct interface *ifp) ei->params.type = eigrp_default_iftype(ifp); + eigrp_passive_interface_apply(ifp); eigrp_if_update(ifp); return 0; @@ -154,6 +158,7 @@ static int eigrp_ifp_up(struct interface *ifp) return 0; } + eigrp_passive_interface_apply(ifp); eigrp_if_up(ifp->info); return 0; @@ -368,6 +373,106 @@ bool eigrp_if_is_passive(struct eigrp_interface *ei) return true; } + +/* Utility function for looking up passive interface settings. */ +static int eigrp_passive_nondefault_lookup(struct eigrp *eigrp, const char *ifname) +{ + unsigned int i; + char *str; + + for (i = 0; i < vector_active(eigrp->passive_nondefault); i++) + if ((str = vector_slot(eigrp->passive_nondefault, i)) != NULL) + if (strcmp(str, ifname) == 0) + return i; + return -1; +} + +static void eigrp_passive_interface_apply(struct interface *ifp) +{ + struct eigrp_interface *ei = ifp->info; + struct eigrp *eigrp; + int ifidx; + + if (!ei || !ei->eigrp) + return; + + eigrp = ei->eigrp; + ifidx = (eigrp_passive_nondefault_lookup(eigrp, ifp->name)); + ei->params.passive_interface = (ifidx < 0) ? eigrp->passive_interface_default + : !eigrp->passive_interface_default; + if (IS_DEBUG_EIGRP(zebra, ZEBRA_INTERFACE)) + zlog_debug("interface %s: passive = %d", ifp->name, + ei->params.passive_interface); + +} + +static void eigrp_passive_interface_apply_all(struct eigrp *eigrp) +{ + struct interface *ifp; + struct vrf *vrf; + + vrf = vrf_lookup_by_id(eigrp->vrf_id); + FOR_ALL_INTERFACES (vrf, ifp) + eigrp_passive_interface_apply(ifp); +} + + +/* Passive interface. */ +int eigrp_passive_nondefault_set(struct eigrp *eigrp, const char *ifname) +{ + if (eigrp_passive_nondefault_lookup(eigrp, ifname) >= 0) + /* + * Don't return an error, this can happen after changing + * 'passive-default'. + */ + return NB_OK; + + vector_set(eigrp->passive_nondefault, + XSTRDUP(MTYPE_EIGRP_IF_STRING, ifname)); + + eigrp_passive_interface_apply_all(eigrp); + + return NB_OK; +} + +int eigrp_passive_nondefault_unset(struct eigrp *eigrp, const char *ifname) +{ + int i; + char *str; + + i = eigrp_passive_nondefault_lookup(eigrp, ifname); + if (i < 0) + /* + * Don't return an error, this can happen after changing + * 'passive-default'. + */ + return NB_OK; + + str = vector_slot(eigrp->passive_nondefault, i); + XFREE(MTYPE_EIGRP_IF_STRING, str); + vector_unset(eigrp->passive_nondefault, i); + + eigrp_passive_interface_apply_all(eigrp); + + return NB_OK; +} + + +/* Free all configured eigrp passive-interface settings. */ +void eigrp_passive_nondefault_clean(struct eigrp *eigrp) +{ + unsigned int i; + char *str; + + for (i = 0; i < vector_active(eigrp->passive_nondefault); i++) + if ((str = vector_slot(eigrp->passive_nondefault, i)) != NULL) { + XFREE(MTYPE_EIGRP_IF_STRING, str); + vector_slot(eigrp->passive_nondefault, i) = NULL; + } + eigrp_passive_interface_apply_all(eigrp); +} + + void eigrp_if_set_multicast(struct eigrp_interface *ei) { if (!eigrp_if_is_passive(ei)) { diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h index 28d134fa4bc6..1aef02167019 100644 --- a/eigrpd/eigrp_interface.h +++ b/eigrpd/eigrp_interface.h @@ -32,6 +32,10 @@ extern void eigrp_if_free(struct eigrp_interface *, int); extern int eigrp_if_down(struct eigrp_interface *); extern void eigrp_if_stream_unset(struct eigrp_interface *); +extern void eigrp_passive_nondefault_clean(struct eigrp *); +extern int eigrp_passive_nondefault_set(struct eigrp *, const char *); +extern int eigrp_passive_nondefault_unset(struct eigrp *, const char *); + extern struct eigrp_interface *eigrp_if_lookup_by_local_addr(struct eigrp *, struct interface *, struct in_addr); diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c index f50abb7e48ca..254d986c056d 100644 --- a/eigrpd/eigrp_northbound.c +++ b/eigrpd/eigrp_northbound.c @@ -157,77 +157,89 @@ static int eigrpd_instance_router_id_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: /frr-eigrpd:eigrpd/instance/passive-default + */ +static int eigrpd_instance_passive_default_modify(struct nb_cb_modify_args *args) +{ + struct eigrp *eigrp; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + eigrp = nb_running_get_entry(args->dnode, NULL, true); + eigrp->passive_interface_default = yang_dnode_get_bool(args->dnode, NULL); + eigrp_passive_nondefault_clean(eigrp); + + return NB_OK; +} + /* * XPath: /frr-eigrpd:eigrpd/instance/passive-interface */ static int eigrpd_instance_passive_interface_create(struct nb_cb_create_args *args) { - struct eigrp_interface *eif; struct eigrp *eigrp; const char *ifname; - switch (args->event) { - case NB_EV_VALIDATE: - eigrp = nb_running_get_entry(args->dnode, NULL, false); - if (eigrp == NULL) { - /* - * XXX: we can't verify if the interface exists - * and is active until EIGRP is up. - */ - break; - } + if (args->event != NB_EV_APPLY) + return NB_OK; - ifname = yang_dnode_get_string(args->dnode, NULL); - eif = eigrp_interface_lookup(eigrp, ifname); - if (eif == NULL) - return NB_ERR_INCONSISTENCY; - break; - case NB_EV_PREPARE: - case NB_EV_ABORT: - /* NOTHING */ - break; - case NB_EV_APPLY: - eigrp = nb_running_get_entry(args->dnode, NULL, true); - ifname = yang_dnode_get_string(args->dnode, NULL); - eif = eigrp_interface_lookup(eigrp, ifname); - if (eif == NULL) - return NB_ERR_INCONSISTENCY; + eigrp = nb_running_get_entry(args->dnode, NULL, true); + ifname = yang_dnode_get_string(args->dnode, NULL); + return eigrp_passive_nondefault_set(eigrp, ifname); +} - eif->params.passive_interface = EIGRP_IF_PASSIVE; - break; - } +static int +eigrpd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args) +{ + struct eigrp *eigrp; + const char *ifname; - return NB_OK; + if (args->event != NB_EV_APPLY) + return NB_OK; + + eigrp = nb_running_get_entry(args->dnode, NULL, true); + ifname = yang_dnode_get_string(args->dnode, NULL); + + return eigrp_passive_nondefault_unset(eigrp, ifname); } +/* + * XPath: /frr-eigrpd:eigrpd/instance/non-passive-interface + */ static int -eigrpd_instance_passive_interface_destroy(struct nb_cb_destroy_args *args) +eigrpd_instance_non_passive_interface_create(struct nb_cb_create_args *args) { - struct eigrp_interface *eif; struct eigrp *eigrp; const char *ifname; - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - /* NOTHING */ - break; - case NB_EV_APPLY: - eigrp = nb_running_get_entry(args->dnode, NULL, true); - ifname = yang_dnode_get_string(args->dnode, NULL); - eif = eigrp_interface_lookup(eigrp, ifname); - if (eif == NULL) - break; + if (args->event != NB_EV_APPLY) + return NB_OK; - eif->params.passive_interface = EIGRP_IF_ACTIVE; - break; - } + eigrp = nb_running_get_entry(args->dnode, NULL, true); + ifname = yang_dnode_get_string(args->dnode, NULL); + eigrp_passive_nondefault_set(eigrp, ifname); return NB_OK; } +static int +eigrpd_instance_non_passive_interface_destroy(struct nb_cb_destroy_args *args) +{ + struct eigrp *eigrp; + const char *ifname; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + eigrp = nb_running_get_entry(args->dnode, NULL, true); + ifname = yang_dnode_get_string(args->dnode, NULL); + + return eigrp_passive_nondefault_unset(eigrp, ifname); +} + /* * XPath: /frr-eigrpd:eigrpd/instance/active-time */ @@ -1307,6 +1319,13 @@ const struct frr_yang_module_info frr_eigrpd_info = { .cli_show = eigrp_cli_show_router_id, } }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/passive-default", + .cbs = { + .cli_show = eigrpd_cli_show_passive_default, + .modify = eigrpd_instance_passive_default_modify, + } + }, { .xpath = "/frr-eigrpd:eigrpd/instance/passive-interface", .cbs = { @@ -1315,6 +1334,14 @@ const struct frr_yang_module_info frr_eigrpd_info = { .cli_show = eigrp_cli_show_passive_interface, } }, + { + .xpath = "/frr-eigrpd:eigrpd/instance/non-passive-interface", + .cbs = { + .create = eigrpd_instance_non_passive_interface_create, + .destroy = eigrpd_instance_non_passive_interface_destroy, + .cli_show = eigrp_cli_show_non_passive_interface, + } + }, { .xpath = "/frr-eigrpd:eigrpd/instance/active-time", .cbs = { diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h index b0e981c73044..2b033b5b1eff 100644 --- a/eigrpd/eigrp_structs.h +++ b/eigrpd/eigrp_structs.h @@ -18,6 +18,7 @@ #define _ZEBRA_EIGRP_STRUCTS_H_ #include "filter.h" +#include "vector.h" #include "eigrpd/eigrp_const.h" #include "eigrpd/eigrp_macros.h" @@ -60,7 +61,10 @@ struct eigrp { struct in_addr router_id_static; /* Configured manually. */ struct list *eiflist; /* eigrp interfaces */ - uint8_t passive_interface_default; /* passive-interface default */ + bool passive_interface_default; /* passive-interface default */ + + /* Vector to store passive-interface name. */ + vector passive_nondefault; int fd; unsigned int maxsndbuflen; diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c index c7dd96bfff3d..9baad53ac2fc 100644 --- a/eigrpd/eigrpd.c +++ b/eigrpd/eigrpd.c @@ -140,6 +140,7 @@ static struct eigrp *eigrp_new(uint16_t as, vrf_id_t vrf_id) /* init internal data structures */ eigrp->eiflist = list_new(); + eigrp->passive_nondefault = vector_init(1); eigrp->passive_interface_default = EIGRP_IF_ACTIVE; eigrp->networks = eigrp_topology_new(); @@ -267,8 +268,10 @@ void eigrp_finish_final(struct eigrp *eigrp) list_delete(&eigrp->eiflist); list_delete(&eigrp->oi_write_q); - eigrp_topology_free(eigrp, eigrp->topology_table); + eigrp_passive_nondefault_clean(eigrp); + vector_free(eigrp->passive_nondefault); + eigrp_topology_free(eigrp, eigrp->topology_table); eigrp_nbr_delete(eigrp->neighbor_self); list_delete(&eigrp->topology_changes_externalIPV4); diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index e9071c897199..76fa73d743d8 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -127,9 +127,26 @@ module frr-eigrpd { type inet:ipv4-address; } + leaf passive-default { + type boolean; + default "false"; + description + "Control whether interfaces are in the passive mode + by default or not."; + } leaf-list passive-interface { - description "List of suppressed interfaces"; + when "../passive-default = 'false'"; + type frr-interface:interface-ref; + description + "A list of interfaces where the sending of EIGRP packets + is disabled."; + } + leaf-list non-passive-interface { + when "../passive-default = 'true'"; type frr-interface:interface-ref; + description + "A list of interfaces where the sending of EIGRP packets + is enabled."; } leaf active-time {