diff options
| -rw-r--r-- | bgpd/bgp_fsm.c | 20 | ||||
| -rw-r--r-- | bgpd/bgp_network.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 6 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 42 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 4 | ||||
| -rwxr-xr-x | configure.ac | 6 | ||||
| -rw-r--r-- | doc/developer/index.rst | 1 | ||||
| -rw-r--r-- | doc/developer/vtysh.rst | 201 | ||||
| -rw-r--r-- | doc/developer/workflow.rst | 58 | ||||
| -rw-r--r-- | lib/distribute.c | 60 | ||||
| -rw-r--r-- | pimd/pim_ifchannel.c | 19 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 8 | ||||
| -rw-r--r-- | staticd/static_routes.c | 60 | ||||
| -rw-r--r-- | staticd/static_routes.h | 2 | ||||
| -rw-r--r-- | staticd/static_zebra.c | 14 | ||||
| -rw-r--r-- | zebra/zebra_l2_null.c | 72 |
17 files changed, 473 insertions, 105 deletions
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 1f0cfd6e25..b70c8bbd63 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -935,9 +935,29 @@ static void bgp_update_delay_process_status_change(struct peer *peer) read/write and timer thread. */ void bgp_fsm_change_status(struct peer *peer, int status) { + struct bgp *bgp; + uint32_t peer_count; bgp_dump_state(peer, peer->status, status); + bgp = peer->bgp; + peer_count = bgp->established_peers; + + if (status == Established) + bgp->established_peers++; + else if ((peer->status == Established) && (status != Established)) + bgp->established_peers--; + + if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) + zlog_debug("%s : vrf %u, established_peers %u", __func__, + bgp->vrf_id, bgp->established_peers); + /* Set to router ID to the value provided by RIB if there are no peers + * in the established state and peer count did not change + */ + if ((peer_count != bgp->established_peers) && + (bgp->established_peers == 0)) + bgp_router_id_zebra_bump(bgp->vrf_id, NULL); + /* Transition into Clearing or Deleted must /always/ clear all routes.. * (and must do so before actually changing into Deleted.. */ diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index a310b7ba74..e15b8f4ec3 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -709,8 +709,10 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address) return -1; } if (bgp_option_check(BGP_OPT_NO_ZEBRA) && - bgp->vrf_id != VRF_DEFAULT) + bgp->vrf_id != VRF_DEFAULT) { + freeaddrinfo(ainfo_save); return -1; + } count = 0; for (ainfo = ainfo_save; ainfo; ainfo = ainfo->ai_next) { int sock; diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index f7c4175383..fc27c546b4 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -4076,6 +4076,11 @@ DEFUN (no_set_aspath_exclude, return ret; } +ALIAS(no_set_aspath_exclude, no_set_aspath_exclude_all_cmd, + "no set as-path exclude", + NO_STR SET_STR + "Transform BGP AS_PATH attribute\n" + "Exclude from the as-path\n") DEFUN (set_community, set_community_cmd, @@ -4965,6 +4970,7 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); + install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &set_origin_cmd); install_element(RMAP_NODE, &no_set_origin_cmd); install_element(RMAP_NODE, &set_atomic_aggregate_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index fd7b8f445b..85b6414e48 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -14140,6 +14140,7 @@ DEFUN (no_community_list_expanded_all, zlog_warn("Deprecated option: 'no ip community-list <(1-99)|(100-500)|standard|expanded> <deny|permit> AA:NN' being used"); } + idx = 0; argv_find(argv, argc, "permit", &idx); argv_find(argv, argc, "deny", &idx); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a078c4f587..48a3b1bb09 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -274,6 +274,10 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id) { struct listnode *node, *nnode; struct bgp *bgp; + struct in_addr *addr = NULL; + + if (router_id != NULL) + addr = (struct in_addr *)&(router_id->u.prefix4); if (vrf_id == VRF_DEFAULT) { /* Router-id change for default VRF has to also update all @@ -282,17 +286,43 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id) if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) continue; - bgp->router_id_zebra = router_id->u.prefix4; - if (!bgp->router_id_static.s_addr) - bgp_router_id_set(bgp, &router_id->u.prefix4); + if (addr) + bgp->router_id_zebra = *addr; + else + addr = &bgp->router_id_zebra; + + if (!bgp->router_id_static.s_addr) { + /* Router ID is updated if there are no active + * peer sessions + */ + if (bgp->established_peers == 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("RID change : vrf %u, RTR ID %s", + bgp->vrf_id, inet_ntoa(*addr)); + bgp_router_id_set(bgp, addr); + } + } } } else { bgp = bgp_lookup_by_vrf_id(vrf_id); if (bgp) { - bgp->router_id_zebra = router_id->u.prefix4; + if (addr) + bgp->router_id_zebra = *addr; + else + addr = &bgp->router_id_zebra; + + if (!bgp->router_id_static.s_addr) { + /* Router ID is updated if there are no active + * peer sessions + */ + if (bgp->established_peers == 0) { + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("RID change : vrf %u, RTR ID %s", + bgp->vrf_id, inet_ntoa(*addr)); + bgp_router_id_set(bgp, addr); + } + } - if (!bgp->router_id_static.s_addr) - bgp_router_id_set(bgp, &router_id->u.prefix4); } } } diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 606da03a8d..725fe1ac9b 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -542,6 +542,9 @@ struct bgp { /* local esi hash table */ struct hash *esihash; + /* Count of peers in established state */ + uint32_t established_peers; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(bgp) @@ -1886,5 +1889,4 @@ extern void bgp_update_redist_vrf_bitmaps(struct bgp *, vrf_id_t); /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); - #endif /* _QUAGGA_BGPD_H */ diff --git a/configure.ac b/configure.ac index 13f6fdab72..c925509faf 100755 --- a/configure.ac +++ b/configure.ac @@ -334,6 +334,12 @@ _LT_CONFIG_LIBTOOL([ ]) if test "$enable_static_bin" = "yes"; then AC_LDFLAGS="-static" + if test "$enable_static" != "yes"; then + AC_MSG_ERROR([The --enable-static-bin option must be combined with --enable-static.]) + fi +fi +if test "$enable_shared" != "yes"; then + AC_MSG_ERROR([FRR cannot be built with --disable-shared. If you want statically linked daemons, use --enable-shared --enable-static --enable-static-bin]) fi AC_SUBST([AC_LDFLAGS]) AM_CONDITIONAL([STATIC_BIN], [test "x$enable_static_bin" = "xyes"]) diff --git a/doc/developer/index.rst b/doc/developer/index.rst index 42192db637..9838e1098c 100644 --- a/doc/developer/index.rst +++ b/doc/developer/index.rst @@ -12,3 +12,4 @@ FRRouting Developer's Guide bgpd ospf zebra + vtysh diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst new file mode 100644 index 0000000000..4a52eb0544 --- /dev/null +++ b/doc/developer/vtysh.rst @@ -0,0 +1,201 @@ +.. _vtysh: + +***** +VTYSH +***** + +.. seealso:: :ref:`command-line-interface` + +.. _vtysh-architecture: + +Architecture +============ + +VTYSH is a shell for FRR daemons. It amalgamates all the CLI commands defined +in each of the daemons and presents them to the user in a single shell, which +saves the user from having to telnet to each of the daemons and use their +individual shells. The amalgamation is achieved by +:ref:`extracting <vtysh-command-extraction>` commands from daemons and +injecting them into VTYSH at build time. + +At runtime, VTYSH maintains an instance of a CLI mode tree just like each +daemon. However, the mode tree in VTYSH contains (almost) all commands from +every daemon in the same tree, whereas individual daemons have trees that only +contain commands relevant to themselves. VTYSH also uses the library CLI +facilities to maintain the user's current position in the tree (the current +node). Note that this position must be synchronized with all daemons; if a +daemon receives a command that causes it to change its current node, VTYSH must +also change its node. Since the extraction script does not understand the +handler code of commands, but only their definitions, this and other behaviors +must be manually programmed into VTYSH for every case where the internal state +of VTYSH must change in response to a command. Details on how this is done are +discussed in the :ref:`vtysh-special-defuns` section. + +VTYSH also handles writing and applying the integrated configuration file, +:file:`/etc/frr/frr.conf`. Since it has knowledge of the entire command space +of FRR, it can intelligently distribute configuration commands only to the +daemons that understand them. Similarly, when writing the configuration file it +takes care of combining multiple instances of configuration blocks and +simplifying the output. This is discussed in :ref:`vtysh-configuration`. + +.. _vtysh-command-extraction: + +Command Extraction +------------------ + +When VTYSH is a built, a Perl script named :file:`extract.pl` searches the FRR +codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms +them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH`` +contains the name of the command plus ``_vtysh``, as well as a flag that +indicates which daemons the command was found in. When the command is executed +in VTYSH, this flag is inspected to determine which daemons to send the command +to. This way, commands are only sent to the daemons that know about them, +avoiding spurious errors from daemons that don't have the command defined. + +The extraction script contains lots of hardcoded knowledge about what sources +to look at and what flags to use for certain commands. + +.. _vtysh-special-defuns: + +Special DEFUNs +-------------- + +In addition to the vanilla ``DEFUN`` macro for defining CLI commands, there are +several VTYSH-specific ``DEFUN`` variants that each serve different purposes. + +``DEFSH`` + Used almost exclusively by generated VTYSH code. This macro defines a + ``cmd_element`` with no handler function; the command, when executed, is + simply forwarded to the daemons indicated in the daemon flag. + +``DEFUN_NOSH`` + Used by daemons. Has the same expansion as a ``DEFUN``, but ``extract.pl`` + will skip these definitions when extracting commands. This is typically used + when VTYSH must take some special action upon receiving the command, and the + programmer therefore needs to write VTYSH's copy of the command manually + instead of using the generated version. + +``DEFUNSH`` + The same as ``DEFUN``, but with an argument that allows specifying the + ``->daemon`` field of the generated ``cmd_element``. This is used by VTYSH + to determine which daemons to send the command to. + +``DEFUNSH_ATTR`` + A version of ``DEFUNSH`` that allows setting the ``->attr`` field of the + generated ``cmd_element``. Not used in practice. + +.. _vtysh-configuration: + +Configuration Management +------------------------ + +When integrated configuration is used, VTYSH manages writing, reading and +applying the FRR configuration file. VTYSH can be made to read and apply an +integrated configuration to all running daemons by launching it with ``-f +<file>``. It sends the appropriate configuration lines to the relevant daemons +in the same way that commands entered by the user on VTYSH's shell prompt are +processed. + +Configuration writing is more complicated. VTYSH makes a best-effort attempt to +combine and simplify the configuration as much as possible. A working example +is best to explain this behavior. + +Example +^^^^^^^ + +Suppose we have just *staticd* and *zebra* running on the system, and use VTYSH +to apply the following configuration snippet: + +.. code-block:: frr + + ! + vrf blue + ip protocol static route-map ExampleRoutemap + ip route 192.168.0.0/24 192.168.0.1 + exit-vrf + ! + +Note that *staticd* defines static route commands and *zebra* defines ``ip +protocol`` commands. Therefore if we ask only *zebra* for its configuration, we +get the following:: + + (config)# do sh running-config zebra + Building configuration... + + ... + ! + vrf blue + ip protocol static route-map ExampleRoutemap + exit-vrf + ! + ... + +Note that the static route doesn't show up there. Similarly, if we ask +*staticd* for its configuration, we get:: + + (config)# do sh running-config staticd + + ... + ! + vrf blue + ip route 192.168.0.0/24 192.168.0.1 + exit-vrf + ! + ... + +But when we display the configuration with VTYSH, we see:: + + ubuntu-bionic(config)# do sh running-config + + ... + ! + vrf blue + ip protocol static route-map ExampleRoutemap + ip route 192.168.0.0/24 192.168.0.1 + exit-vrf + ! + ... + +This is because VTYSH asks each daemon for its currently running configuration, +and combines equivalent blocks together. In the above example, it combined the +``vrf blue`` blocks from both *zebra* and *staticd* together into one. This is +done in :file:`vtysh_config.c`. + +Protocol +======== + +VTYSH communicates with FRR daemons by way of domain socket. Each daemon +creates its own socket, typically in :file:`/var/run/frr/<daemon>.vty`. The +protocol is very simple. In the VTYSH to daemon direction, messages are simply +NULL-terminated strings, whose content are CLI commands. Here is a typical +message from VTYSH to a daemon: + +:: + + Request + + 00000000: 646f 2077 7269 7465 2074 6572 6d69 6e61 do write termina + 00000010: 6c0a 00 l.. + + +The response format has some more data in it. First is a NULL-terminated string +containing the plaintext response, which is just the output of the command that +was sent in the request. This is displayed to the user. The plaintext response +is followed by 3 null marker bytes, followed by a 1-byte status code that +indicates whether the command was successful or not. + +:: + + Response + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Plaintext Response | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Marker (0x00) | Status Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +The first ``0x00`` byte in the marker also serves to terminate the plaintext +response. diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index ee7592fd6a..543dfdd3b9 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -91,17 +91,63 @@ documentation and packaging systems will be updated to reflect the next possible release name to allow for easy distinguishing. After one month the development branch will be renamed to -``stable/MAJOR.MINOR``. This process is not held up unless a crash or security -issue has been found and needs to be addressed. Issues being fixed will not -cause a delay. +``stable/MAJOR.MINOR``. The branch is a stable branch. This process is not +held up unless a crash or security issue has been found and needs to +be addressed. Issues being fixed will not cause a delay. Bugfix releases are made as needed at 1 month intervals until the next -``MAJOR.MINOR`` relese branch is pulled. Depending on the severity of the bugs, +``MAJOR.MINOR`` release branch is pulled. Depending on the severity of the bugs, bugfix releases may occur sooner. Bugfixes are applied to the two most recent releases. Security fixes are -backported to all releases less than or equal to one year old. Security fixes -may also be backported to older releases depending on severity. +backported to all releases less than or equal to at least one year old. Security +fixes may also be backported to older releases depending on severity. + +Long term support branches ( LTS ) +----------------------------------------- + +This kind of branch is not yet officially supported, and need experimentation +before being effective. + +Previous definition of releases prevents long term support of previous releases. +For instance, bug and security fixes are not applied if the stable branch is too +old. + +Because the FRR users have a need to backport bug and security fixes after the +stable branch becomes too old, there is a need to provide support on a long term +basis on that stable branch. If that support is applied on that stable branch, +then that branch is a long term support branch. + +Having a LTS branch requires extra-work and requires one person to be in charge +of that maintenance branch for a certain amount of time. The amount of time will +be by default set to 4 months, and can be increased. 4 months stands for the time +between two releases, this time can be applied to the decision to continue with a +LTS release or not. In all cases, that time period will be well-defined and +published. Also, a self nomination from a person that proposes to handle the LTS +branch is required. The work can be shared by multiple people. In all cases, there +must be at least one person that is in charge of the maintenance branch. The person +on people responsible for a maintenance branch must be a FRR maintainer. Note that +they may choose to abandon support for the maintenance branch at any time. If +noone takes over the responsibility of the LTS branch, then the support will be +discontinued. + +The LTS branch duties are the following ones: + +- organise meetings on a (bi-)weekly or monthly basis, the handling of issues + and pull requested relative to that branch. When time permits, this may be done + during the regularly scheduled FRR meeting. + +- ensure the stability of the branch, by using and eventually adapting the + checking the CI tools of FRR ( indeed, maintaining may lead to create + maintenance branches for topotests or for CI). + +It will not be possible to backport feature requests to LTS branches. Actually, it +is a false good idea to use LTS for that need. Introducing feature requests may +break the paradigm where all more recent releases should also include the feature +request. This would require the LTS maintainer to ensure that all more recent +releases have support for this feature request. Moreover, introducing features +requests may result in breaking the stability of the branch. LTS branches are first +done to bring long term support for stability. Changelog --------- diff --git a/lib/distribute.c b/lib/distribute.c index 0f1d666aeb..9697916332 100644 --- a/lib/distribute.c +++ b/lib/distribute.c @@ -299,16 +299,15 @@ DEFUN (ipv6_distribute_list, ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - distfn(ifname, type, argv[1 + prefix]->arg); + distfn(ifname, type, argv[2 + prefix]->arg); return CMD_SUCCESS; } DEFUN (no_distribute_list, no_distribute_list_cmd, - "no [ipv6] distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] WORD <in|out> [WORD]", NO_STR - "IPv6\n" "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -316,20 +315,53 @@ DEFUN (no_distribute_list, "Filter outgoing routing updates\n" "Interface name\n") { - int ipv6 = strmatch(argv[1]->text, "ipv6"); - int prefix = (argv[2 + ipv6]->type == WORD_TKN) ? 1 : 0; + int prefix = (argv[2]->type == WORD_TKN) ? 1 : 0; - int idx_alname = 2 + ipv6 + prefix; + int idx_alname = 2 + prefix; int idx_disttype = idx_alname + 1; + enum distribute_type type = + argv[idx_disttype]->arg[0] == 'i' ? + DISTRIBUTE_V4_IN : DISTRIBUTE_V4_OUT; - /* Check of distribute list type. */ - enum distribute_type distin = - (ipv6) ? DISTRIBUTE_V6_IN : DISTRIBUTE_V4_IN; - enum distribute_type distout = - (ipv6) ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V4_OUT; + /* Set appropriate function call */ + int (*distfn)(const char *, enum distribute_type, + const char *) = + prefix ? &distribute_list_prefix_unset : &distribute_list_unset; + + /* if interface is present, get name */ + const char *ifname = NULL; + if (argv[argc - 1]->type == VARIABLE_TKN) + ifname = argv[argc - 1]->arg; + /* Get interface name corresponding distribute list. */ + int ret = distfn(ifname, type, argv[2 + prefix]->arg); + + if (!ret) { + vty_out(vty, "distribute list doesn't exist\n"); + return CMD_WARNING_CONFIG_FAILED; + } + return CMD_SUCCESS; +} + +DEFUN (no_ipv6_distribute_list, + no_ipv6_distribute_list_cmd, + "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + NO_STR + "IPv6\n" + "Filter networks in routing updates\n" + "Specify a prefix\n" + "Access-list name\n" + "Filter incoming routing updates\n" + "Filter outgoing routing updates\n" + "Interface name\n") +{ + int prefix = (argv[3]->type == WORD_TKN) ? 1 : 0; + + int idx_alname = 3 + prefix; + int idx_disttype = idx_alname + 1; enum distribute_type type = - argv[idx_disttype]->arg[0] == 'i' ? distin : distout; + argv[idx_disttype]->arg[0] == 'i' ? + DISTRIBUTE_V6_IN : DISTRIBUTE_V6_OUT; /* Set appropriate function call */ int (*distfn)(const char *, enum distribute_type, const char *) = @@ -337,10 +369,11 @@ DEFUN (no_distribute_list, /* if interface is present, get name */ const char *ifname = NULL; + if (argv[argc - 1]->type == VARIABLE_TKN) ifname = argv[argc - 1]->arg; /* Get interface name corresponding distribute list. */ - int ret = distfn(ifname, type, argv[2 + prefix]->arg); + int ret = distfn(ifname, type, argv[3 + prefix]->arg); if (!ret) { vty_out(vty, "distribute list doesn't exist\n"); @@ -535,6 +568,7 @@ void distribute_list_init(int node) /* install v6 */ if (node == RIPNG_NODE) { install_element(RIPNG_NODE, &ipv6_distribute_list_cmd); + install_element(RIPNG_NODE, &no_ipv6_distribute_list_cmd); } /* TODO: install v4 syntax command for v6 only protocols. */ diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 129d569c87..8f6a9ece53 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1012,10 +1012,21 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, /* PIM enabled on interface? */ pim_ifp = ifp->info; - if (!pim_ifp) + if (!pim_ifp) { + if (PIM_DEBUG_EVENTS) + zlog_debug("%s:%s Expected pim interface setup for %s", + __PRETTY_FUNCTION__, + pim_str_sg_dump(sg), ifp->name); return 0; - if (!PIM_IF_TEST_PIM(pim_ifp->options)) + } + + if (!PIM_IF_TEST_PIM(pim_ifp->options)) { + if (PIM_DEBUG_EVENTS) + zlog_debug("%s:%s PIM is not configured on this interface %s", + __PRETTY_FUNCTION__, + pim_str_sg_dump(sg), ifp->name); return 0; + } pim = pim_ifp->pim; @@ -1033,6 +1044,10 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); if (!ch) { + if (PIM_DEBUG_EVENTS) + zlog_debug("%s:%s Unable to add ifchannel", + __PRETTY_FUNCTION__, + pim_str_sg_dump(sg)); return 0; } diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3dfc36a0c2..10ea17cf1f 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -1048,6 +1048,10 @@ void igmp_source_forward_start(struct pim_instance *pim, __PRETTY_FUNCTION__, pim_str_sg_dump(&sg), group->group_igmp_sock->interface->name); + + pim_channel_del_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); return; } /* @@ -1059,6 +1063,10 @@ void igmp_source_forward_start(struct pim_instance *pim, if (PIM_DEBUG_MROUTE) zlog_warn("%s: Failure to add local membership for %s", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); + + pim_channel_del_oif(source->source_channel_oil, + group->group_igmp_sock->interface, + PIM_OIF_FLAG_PROTO_IGMP); return; } diff --git a/staticd/static_routes.c b/staticd/static_routes.c index cd0330ed82..a5f0f74b00 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -497,6 +497,66 @@ void static_cleanup_vrf_ids(struct static_vrf *disable_svrf) } } +/* + * This function enables static routes when an interface it relies + * on in a different vrf is coming up. + * + * stable -> The stable we are looking at. + * ifp -> interface coming up + * afi -> the afi in question + * safi -> the safi in question + */ +static void static_fixup_intf_nh(struct route_table *stable, + struct interface *ifp, + afi_t afi, safi_t safi) +{ + struct route_node *rn; + struct static_route *si; + + for (rn = route_top(stable); rn; rn = route_next(rn)) { + for (si = rn->info; si; si = si->next) { + if (si->nh_vrf_id != ifp->vrf_id) + continue; + + if (si->ifindex != ifp->ifindex) + continue; + + static_install_route(rn, si, safi); + } + } +} + +/* + * This function enables static routes that rely on an interface in + * a different vrf when that interface comes up. + */ +void static_install_intf_nh(struct interface *ifp) +{ + struct route_table *stable; + struct vrf *vrf; + afi_t afi; + safi_t safi; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + struct static_vrf *svrf = vrf->info; + + /* Not needed if same vrf since happens naturally */ + if (vrf->vrf_id == ifp->vrf_id) + continue; + + /* Install any static routes configured for this interface. */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + stable = svrf->stable[afi][safi]; + if (!stable) + continue; + + static_fixup_intf_nh(stable, ifp, afi, safi); + } + } + } +} + /* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */ void static_ifindex_update(struct interface *ifp, bool up) { diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 916ddcd7eb..6036bfe396 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -113,5 +113,7 @@ extern int static_delete_route(afi_t afi, safi_t safi, uint8_t type, extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf); +extern void static_install_intf_nh(struct interface *ifp); + extern void static_ifindex_update(struct interface *ifp, bool up); #endif diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index fd4201e562..1e23f597b0 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -122,11 +122,17 @@ static int interface_state_up(int command, struct zclient *zclient, ifp = zebra_interface_if_lookup(zclient->ibuf); - if (ifp && if_is_vrf(ifp)) { - struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id); + if (ifp) { + if (if_is_vrf(ifp)) { + struct static_vrf *svrf = + static_vrf_lookup_by_id(vrf_id); - static_fixup_vrf_ids(svrf); - static_config_install_delayed_routes(svrf); + static_fixup_vrf_ids(svrf); + static_config_install_delayed_routes(svrf); + } + + /* Install any static reliant on this interface coming up */ + static_install_intf_nh(ifp); } return 0; diff --git a/zebra/zebra_l2_null.c b/zebra/zebra_l2_null.c deleted file mode 100644 index c063f77bd4..0000000000 --- a/zebra/zebra_l2_null.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Zebra Layer-2 interface Data structures and definitions - * Copyright (C) 2016, 2017 Cumulus Networks, Inc. - * - * This file is part of FRR. - * - * FRR is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * FRR is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with FRR; see the file COPYING. If not, write to the Free - * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include <zebra.h> - -#include "if.h" -#include "zebra/debug.h" -#include "zebra/zserv.h" -#include "zebra/rib.h" -#include "zebra/zebra_vrf.h" -#include "zebra/zebra_l2.h" - -void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave) -{ -} - -void zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave) -{ -} - -void zebra_l2_bridge_add_update(struct interface *ifp, - struct zebra_l2info_bridge *bridge_info, - int add) -{ -} - -void zebra_l2_bridge_del(struct interface *ifp) -{ -} - -void zebra_l2_vlanif_update(struct interface *ifp, - struct zebra_l2info_vlan *vlan_info) -{ -} - -void zebra_l2_vxlanif_add_update(struct interface *ifp, - struct zebra_l2info_vxlan *vxlan_info, int add) -{ -} - -void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, - vlanid_t access_vlan) -{ -} - -void zebra_l2_vxlanif_del(struct interface *ifp) -{ -} - -void zebra_l2if_update_bridge_slave(struct interface *ifp, - ifindex_t bridge_ifindex) -{ -} |
