}
}
}
+
+void bgp_nht_register_enhe_capability_interfaces(struct peer *peer)
+{
+ struct bgp *bgp;
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
+ struct nexthop *nhop;
+ struct interface *ifp;
+ struct prefix p;
+
+ if (peer->ifp)
+ return;
+
+ bgp = peer->bgp;
+
+ if (!bgp->nexthop_cache_table[AFI_IP6])
+ return;
+
+ if (!sockunion2hostprefix(&peer->su, &p)) {
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s: Unable to convert prefix to sockunion",
+ __PRETTY_FUNCTION__);
+ return;
+ }
+
+ if (p.family != AF_INET6)
+ return;
+ rn = bgp_node_lookup(bgp->nexthop_cache_table[AFI_IP6], &p);
+
+ bnc = bgp_nexthop_get_node_info(rn);
+ if (!bnc)
+ return;
+
+ if (peer != bnc->nht_info)
+ return;
+
+ for (nhop = bnc->nexthop; nhop; nhop = nhop->next) {
+ ifp = if_lookup_by_index(nhop->ifindex,
+ nhop->vrf_id);
+ zclient_send_interface_radv_req(zclient,
+ nhop->vrf_id,
+ ifp, true,
+ BGP_UNNUM_DEFAULT_RA_INTERVAL);
+ }
+}
*/
extern void bgp_nht_register_nexthops(struct bgp *bgp);
+/*
+ * When we have the the PEER_FLAG_CAPABILITY_ENHE flag
+ * set on a peer *after* it has been brought up we need
+ * to notice and setup the interface based RA,
+ * this code can walk the registered nexthops and
+ * register the important ones with zebra for RA.
+ */
+extern void bgp_nht_register_enhe_capability_interfaces(struct peer *peer);
+
#endif /* _BGP_NHT_H */
return 0;
}
+ if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
+ bgp_nht_register_enhe_capability_interfaces(peer);
+
/*
* Update peer-group members, unless they are explicitely overriding
* peer-group configuration.
/* Update flag on peer-group member. */
COND_FLAG(member->flags, flag, set != member_invert);
+ if (set && flag == PEER_FLAG_CAPABILITY_ENHE)
+ bgp_nht_register_enhe_capability_interfaces(member);
+
/* Execute flag action on peer-group member. */
if (action.type == peer_change_reset)
peer_flag_modify_action(member, flag);
Add init.d startup files
^^^^^^^^^^^^^^^^^^^^^^^^
-.. code-block::
+.. code-block:: shell
sudo install -p -m 755 redhat/frr.init /etc/init.d/frr
sudo chkconfig --add frr
Enable FRR daemon at startup
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. code-block::
+.. code-block:: shell
sudo chkconfig frr on
Start FRR manually (or reboot)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-.. code-block::
+.. code-block:: shell
sudo /etc/init.d/frr start
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Although not strictly necessary, it's good practice to create empty
-configuration files _before_ starting FRR. This assures that the permissions
+configuration files _before_ starting FRR. This assures that the permissions
are correct. If the files are not already present, FRR will create them.
It's also important to consider _which_ files to create. FRR supports writing
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
-exclude_patterns = ['_build']
+exclude_patterns = ['_build', 'building-libyang.rst']
# The reST default role (used for this markup: `text`) to use for all
# documents.
-Release Build Procedure for FRR maintainers
-=========================================================
+Release Build Procedure for FRR Maintainers
+===========================================
1. Rename branch (if needed)
Command line parameters
-----------------------
-Command line parameters can be passed directly to a module by appending a
-colon to the module name when loading it, e.g. ``-M mymodule:myparameter``.
-The text after the colon will be accessible in the module's code through
+Command line parameters can be passed directly to a module by appending a
+colon to the module name when loading it, e.g. ``-M mymodule:myparameter``.
+The text after the colon will be accessible in the module's code through
``THIS_MODULE->load_args``. For example, see how the format parameter is
configured in the ``zfpm_init()`` function inside ``zebra_fpm.c``.
O O
/ \
O O
-
+
struct rnh
{
uint8_t flags;
-Debian
-======
+Packaging Debian
+================
(Tested on Ubuntu 12.04, 14.04, 16.04, 17.10, 18.04, Debian 8 and 9)
.. toctree::
:maxdepth: 2
+ maintainer-release-build
packaging-debian
.. todo: replace these with SVG
.. figure:: ../figures/threadmaster-single.png
:align: center
-
+
Lifecycle of a program using a single threadmaster.
The series of "task" boxes represents the current ready task queue. The various
.. todo: replace these with SVG
.. figure:: ../figures/threadmaster-multiple.png
:align: center
-
+
Lifecycle of a program using multiple pthreads, each running their own
``threadmaster``
appropriate value.
:makevar:`VRF forwarding`
- General information on Linux VRF support can be found in
+ General information on Linux VRF support can be found in
https://www.kernel.org/doc/Documentation/networking/vrf.txt. Kernel
support for VRFs was introduced in 4.3 and improved upon through
4.13, which is the version most used in FRR testing (as of June
included in future kernel versions so upgrading your kernel may also
address this issue.
-
+
Building
^^^^^^^^
ISIS router
===========
-To start ISIS process you have to specify the ISIS router. As of this
+To start the ISIS process you have to specify the ISIS router. As of this
writing, *isisd* does not support multiple ISIS processes.
-.. index:: router isis WORD
-.. clicmd:: router isis WORD
-
-.. index:: no router isis WORD
-.. clicmd:: no router isis WORD
+.. index:: [no] router isis WORD
+.. clicmd:: [no] router isis WORD
Enable or disable the ISIS process by specifying the ISIS domain with
'WORD'. *isisd* does not yet support multiple ISIS processes but you must
ISIS interface
==============
-.. index:: ip router isis WORD
-.. clicmd:: ip router isis WORD
-
-.. index:: no ip router isis WORD
-.. clicmd:: no ip router isis WORD
-
.. _ip-router-isis-word:
- Activate ISIS adjacency on this interface. Note that the name
- of ISIS instance must be the same as the one used to configure the ISIS process
- (see command :clicmd:`router isis WORD`).
+.. index:: [no] <ip|ipv6> router isis WORD
+.. clicmd:: [no] <ip|ipv6> router isis WORD
+
+ Activate ISIS adjacency on this interface. Note that the name of ISIS
+ instance must be the same as the one used to configure the ISIS process (see
+ command :clicmd:`router isis WORD`). To enable IPv4, issue ``ip router isis
+ WORD``; to enable IPv6, issue ``ipv6 router isis WORD``.
.. index:: isis circuit-type [level-1 | level-1-2 | level-2]
.. clicmd:: isis circuit-type [level-1 | level-1-2 | level-2]
.. _starting-static:
-Starting STATIC
+Starting STATIC
===============
Default configuration file for *staticd* is :file:`staticd.conf`. The typical
initial form of the command. GATEWAY is gateway for the prefix it currently
must match the v4 or v6 route type specified at the start of the command.
GATEWAY can also be treated as an interface name. If the interface name
- is ``null0`` then zebra installs a blackhole route. TABLENO
+ is ``null0`` then zebra installs a blackhole route. TABLENO
is an optional parameter for namespaces that allows you to create the
route in a specified table associated with the vrf namespace. table will
be rejected if you are not using namespace based vrfs. ``nexthop-vrf``
- allows you to create a leaked route with a nexthop in the specified VRFNAME
+ allows you to create a leaked route with a nexthop in the specified VRFNAME
vrf VRFNAME allows you to create the route in a specified vrf.
``nexthop-vrf`` cannot be currently used with namespace based vrfs
currently as well.
Enable/disable link-detect on platforms which support this. Currently only
Linux and Solaris, and only where network interface drivers support
reporting link-state via the ``IFF_RUNNING`` flag.
-
+
In FRR, link-detect is on by default.
.. _link-parameters-commands:
}
}
-static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type)
+static void netlink_determine_zebra_iftype(const char *kind,
+ zebra_iftype_t *zif_type)
{
*zif_type = ZEBRA_IF_OTHER;
*zif_type = ZEBRA_IF_MACVLAN;
else if (strcmp(kind, "veth") == 0)
*zif_type = ZEBRA_IF_VETH;
+ else if (strcmp(kind, "bond") == 0)
+ *zif_type = ZEBRA_IF_BOND;
+ else if (strcmp(kind, "bond_slave") == 0)
+ *zif_type = ZEBRA_IF_BOND_SLAVE;
}
#define parse_rtattr_nested(tb, max, rta) \
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
ifindex_t link_ifindex = IFINDEX_INTERNAL;
+ ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif;
zns = zebra_ns_lookup(ns_id);
if (linkinfo[IFLA_INFO_SLAVE_KIND])
slave_kind = RTA_DATA(linkinfo[IFLA_INFO_SLAVE_KIND]);
- netlink_determine_zebra_iftype(kind, &zif_type);
+ if ((slave_kind != NULL) && strcmp(slave_kind, "bond") == 0)
+ netlink_determine_zebra_iftype("bond_slave", &zif_type);
+ else
+ netlink_determine_zebra_iftype(kind, &zif_type);
}
/* If VRF, create the VRF structure itself. */
zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
bridge_ifindex =
*(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+ } else if (slave_kind && (strcmp(slave_kind, "bond") == 0)) {
+ zif_slave_type = ZEBRA_IF_SLAVE_BOND;
+ bond_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
} else
zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], 1);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);
+ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
+ zebra_l2if_update_bond_slave(ifp, bond_ifindex);
return 0;
}
zebra_iftype_t zif_type = ZEBRA_IF_OTHER;
zebra_slave_iftype_t zif_slave_type = ZEBRA_IF_SLAVE_NONE;
ifindex_t bridge_ifindex = IFINDEX_INTERNAL;
+ ifindex_t bond_ifindex = IFINDEX_INTERNAL;
ifindex_t link_ifindex = IFINDEX_INTERNAL;
zif_slave_type = ZEBRA_IF_SLAVE_BRIDGE;
bridge_ifindex =
*(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
+ } else if (slave_kind
+ && (strcmp(slave_kind, "bond") == 0)) {
+ zif_slave_type = ZEBRA_IF_SLAVE_BOND;
+ bond_ifindex =
+ *(ifindex_t *)RTA_DATA(tb[IFLA_MASTER]);
} else
zif_slave_type = ZEBRA_IF_SLAVE_OTHER;
}
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp,
bridge_ifindex);
+ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
+ zebra_l2if_update_bond_slave(ifp, bond_ifindex);
} else if (ifp->vrf_id != vrf_id) {
/* VRF change for an interface. */
if (IS_ZEBRA_DEBUG_KERNEL)
if_handle_vrf_change(ifp, vrf_id);
} else {
- int was_bridge_slave;
+ bool was_bridge_slave, was_bond_slave;
/* Interface update. */
if (IS_ZEBRA_DEBUG_KERNEL)
/* Update interface type - NOTE: Only slave_type can
* change. */
was_bridge_slave = IS_ZEBRA_IF_BRIDGE_SLAVE(ifp);
+ was_bond_slave = IS_ZEBRA_IF_BOND_SLAVE(ifp);
zebra_if_set_ziftype(ifp, zif_type, zif_slave_type);
netlink_interface_update_hw_addr(tb, ifp);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
zebra_l2if_update_bridge_slave(ifp,
bridge_ifindex);
+ else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
+ zebra_l2if_update_bond_slave(ifp, bond_ifindex);
}
} else {
/* Delete interface notification from kernel */
return "VETH";
break;
+ case ZEBRA_IF_BOND:
+ return "bond";
+
+ case ZEBRA_IF_BOND_SLAVE:
+ return "bond_slave";
+
+ case ZEBRA_IF_MACVLAN:
+ return "macvlan";
+
default:
return "Unknown";
break;
br_slave->bridge_ifindex);
}
+ if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) {
+ struct zebra_l2info_bondslave *bond_slave;
+
+ bond_slave = &zebra_if->bondslave_info;
+ if (bond_slave->bond_ifindex != IFINDEX_INTERNAL)
+ vty_out(vty, " Master (bond) ifindex %u\n",
+ bond_slave->bond_ifindex);
+ }
+
if (zebra_if->link_ifindex != IFINDEX_INTERNAL) {
vty_out(vty, " Link ifindex %u", zebra_if->link_ifindex);
if (zebra_if->link)
+
/* Interface function header.
* Copyright (C) 1999 Kunihiro Ishiguro
*
ZEBRA_IF_VLAN, /* VLAN sub-interface */
ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/
ZEBRA_IF_VETH, /* VETH interface*/
+ ZEBRA_IF_BOND, /* Bond */
+ ZEBRA_IF_BOND_SLAVE, /* Bond */
} zebra_iftype_t;
/* Zebra "slave" interface type */
ZEBRA_IF_SLAVE_NONE, /* Not a slave */
ZEBRA_IF_SLAVE_VRF, /* Member of a VRF */
ZEBRA_IF_SLAVE_BRIDGE, /* Member of a bridge */
+ ZEBRA_IF_SLAVE_BOND, /* Bond member */
ZEBRA_IF_SLAVE_OTHER, /* Something else - e.g., bond slave */
} zebra_slave_iftype_t;
*/
struct zebra_l2info_brslave brslave_info;
+ struct zebra_l2info_bondslave bondslave_info;
+
/* Link fields - for sub-interfaces. */
ifindex_t link_ifindex;
struct interface *link;
#define IS_ZEBRA_IF_VRF_SLAVE(ifp) \
(((struct zebra_if *)(ifp->info))->zif_slave_type == ZEBRA_IF_SLAVE_VRF)
+#define IS_ZEBRA_IF_BOND_SLAVE(ifp) \
+ (((struct zebra_if *)(ifp->info))->zif_slave_type \
+ == ZEBRA_IF_SLAVE_BOND)
+
extern void zebra_if_init(void);
extern struct interface *if_lookup_by_index_per_ns(struct zebra_ns *, uint32_t);
br_slave->br_if = NULL;
}
+void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave)
+{
+ struct interface *bond_if;
+
+ /* TODO: Handle change of master */
+ bond_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ bond_slave->bond_ifindex);
+ if (bond_if)
+ bond_slave->bond_if = bond_if;
+}
+
+void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave)
+{
+ if (bond_slave != NULL)
+ bond_slave->bond_if = NULL;
+}
+
/*
* Handle Bridge interface add or update. Update relevant info,
* map slaves (if any) to the bridge.
zebra_l2_unmap_slave_from_bridge(&zif->brslave_info);
}
}
+
+void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex)
+{
+ struct zebra_if *zif;
+ ifindex_t old_bond_ifindex;
+
+ zif = ifp->info;
+ assert(zif);
+
+ old_bond_ifindex = zif->bondslave_info.bond_ifindex;
+ if (old_bond_ifindex == bond_ifindex)
+ return;
+
+ zif->bondslave_info.bond_ifindex = bond_ifindex;
+
+ /* Set up or remove link with master */
+ if (bond_ifindex != IFINDEX_INTERNAL)
+ zebra_l2_map_slave_to_bond(&zif->bondslave_info);
+ else if (old_bond_ifindex != IFINDEX_INTERNAL)
+ zebra_l2_unmap_slave_from_bond(&zif->bondslave_info);
+}
vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
};
+struct zebra_l2info_bondslave {
+ ifindex_t bond_ifindex; /* Bridge Master */
+ struct interface *bond_if; /* Pointer to master */
+};
+
union zebra_l2if_info {
struct zebra_l2info_bridge br;
struct zebra_l2info_vlan vl;
extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
+extern void
+zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave);
+extern void
+zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave);
extern void zebra_l2_bridge_add_update(struct interface *ifp,
struct zebra_l2info_bridge *bridge_info,
int add);
extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t bridge_ifindex);
+extern void zebra_l2if_update_bond_slave(struct interface *ifp,
+ ifindex_t bond_ifindex);
#endif /* _ZEBRA_L2_H */
/* Match function should return 1 if match is success else return
zero. */
-static route_map_result_t route_match_ip_address(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static route_map_result_t route_match_address(afi_t afi, void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
if (type == RMAP_ZEBRA) {
- alist = access_list_lookup(AFI_IP, (char *)rule);
+ alist = access_list_lookup(afi, (char *)rule);
if (alist == NULL)
return RMAP_NOMATCH;
return RMAP_NOMATCH;
}
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+{
+ return route_match_address(AFI_IP, rule, prefix, type, object);
+}
+
+static route_map_result_t route_match_ipv6_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+
+{
+ return route_match_address(AFI_IP6, rule, prefix, type, object);
+}
+
/* Route map `ip address' match statement. `arg' should be
access-list name. */
-static void *route_match_ip_address_compile(const char *arg)
+static void *route_match_address_compile(const char *arg)
{
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
/* Free route map's compiled `ip address' value. */
-static void route_match_ip_address_free(void *rule)
+static void route_match_address_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
/* Route map commands for ip address matching. */
static struct route_map_rule_cmd route_match_ip_address_cmd = {
- "ip address", route_match_ip_address, route_match_ip_address_compile,
- route_match_ip_address_free};
+ "ip address", route_match_ip_address, route_match_address_compile,
+ route_match_address_free};
+
+/* Route map commands for ipv6 address matching. */
+static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
+ "ipv6 address", route_match_ipv6_address, route_match_address_compile,
+ route_match_address_free};
/* `match ip address prefix-list PREFIX_LIST' */
route_map_install_match(&route_match_ip_next_hop_cmd);
route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
route_map_install_match(&route_match_ip_address_cmd);
+ route_map_install_match(&route_match_ipv6_address_cmd);
route_map_install_match(&route_match_ip_address_prefix_list_cmd);
route_map_install_match(&route_match_ipv6_address_prefix_list_cmd);
route_map_install_match(&route_match_ip_address_prefix_len_cmd);