summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_fsm.c20
-rw-r--r--bgpd/bgp_network.c4
-rw-r--r--bgpd/bgp_routemap.c6
-rw-r--r--bgpd/bgp_vty.c1
-rw-r--r--bgpd/bgpd.c42
-rw-r--r--bgpd/bgpd.h4
-rwxr-xr-xconfigure.ac6
-rw-r--r--doc/developer/index.rst1
-rw-r--r--doc/developer/vtysh.rst201
-rw-r--r--doc/developer/workflow.rst58
-rw-r--r--lib/distribute.c60
-rw-r--r--pimd/pim_ifchannel.c19
-rw-r--r--pimd/pim_zebra.c8
-rw-r--r--staticd/static_routes.c60
-rw-r--r--staticd/static_routes.h2
-rw-r--r--staticd/static_zebra.c14
-rw-r--r--zebra/zebra_l2_null.c72
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)
-{
-}