Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BGP EVPN vrf netns backend #5077

Merged
merged 21 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
14ddb3d
zebra: across network namespace, vxlan remembers the link information
pguibert6WIND Sep 24, 2019
2825412
zebra: importation of bgp evpn rt5 from vni with other netns
pguibert6WIND Sep 26, 2019
6fe516b
zebra: zvni_from_svi() adaptation for other network namespaces
pguibert6WIND Sep 27, 2019
2a9dccb
zebra: zvni_map_to_svi() adaptation for other network namespaces
pguibert6WIND Sep 27, 2019
fc31413
zebra: display interface slave type
pguibert6WIND Sep 27, 2019
7c99087
zebra: map vxlan interface to bridge interface with correct ns id
pguibert6WIND Oct 1, 2019
97c9e75
zebra, lib: add an internal API to get relative default nsid in other ns
pguibert6WIND Oct 2, 2019
9d3555e
zebra, lib: store relative default ns id in each namespace
pguibert6WIND Oct 2, 2019
b6ebab3
zebra, lib: new API to get absolute netns val from relative netns val
pguibert6WIND Oct 2, 2019
b5b453a
zebra: bridge layer2 information records ns_id where bridge is
pguibert6WIND Oct 3, 2019
388d5b4
zebra: add ns_id attribute to mac structure
pguibert6WIND Oct 9, 2019
f8ed2c5
zebra: fdb and neighbor table are read for all zns
pguibert6WIND Sep 27, 2019
db81d18
zebra: zvni_map_to_vlan() adaptation for all namespaces
pguibert6WIND Oct 9, 2019
a2342a2
bgpd: evpn nexthop can be changed by default
pguibert6WIND Oct 11, 2019
3acc394
zebra: when parsing local entry against dad, retrieve config
pguibert6WIND Oct 25, 2019
4042454
zebra: local mac entries populated in correct netnamespace
pguibert6WIND Oct 28, 2019
c4d466c
lib, zebra: reuse and adapt ns_list walk functionality
pguibert6WIND Dec 20, 2019
ee9633e
bgpd: sanity check when updating nexthop from bgp to zebra
pguibert6WIND Jan 3, 2020
de0ebb2
zebra: dynamically detect vxlan link interfaces in other netns
pguibert6WIND Jan 6, 2020
89b97c3
doc: add some documentation about bgp evpn netns support
pguibert6WIND Feb 6, 2020
bf69e21
zebra: support for macvlan interfaces
pguibert6WIND Feb 6, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -16234,6 +16234,10 @@ void bgp_vty_init(void)
&no_neighbor_route_reflector_client_cmd);
install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_cmd);
install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd);

/* "neighbor route-server" commands.*/
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
Expand Down
3 changes: 2 additions & 1 deletion bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
api_nh->ifindex = 0;
}
}
api_nh->gate.ipv6 = *nexthop;
if (nexthop)
api_nh->gate.ipv6 = *nexthop;

return true;
}
Expand Down
4 changes: 0 additions & 4 deletions bgpd/bgpd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1227,10 +1227,6 @@ struct peer *peer_new(struct bgp *bgp)
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
}

/* set nexthop-unchanged for l2vpn evpn by default */
SET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN],
PEER_FLAG_NEXTHOP_UNCHANGED);

SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);

/* Initialize per peer bgp GR FSM */
Expand Down
21 changes: 21 additions & 0 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2391,6 +2391,27 @@ the same behavior of using same next-hop and RMAC values.
Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
parameters.

Support with VRF network namespace backend
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
It is possible to separate overlay networks contained in VXLAN interfaces from
underlay networks by using VRFs. VRF-lite and VRF-netns backends can be used for
that. In the latter case, this is necessary to set both bridge and vxlan interface
on the same network namespace, as below example illustrates:

.. code-block:: shell

# linux shell
ip netns add vrf1
ip link add name vxlan101 type vxlan id 101 dstport 4789 dev eth0 local 10.1.1.1
ip link set dev vxlan101 netns vrf1
ip netns exec vrf1 ip link set dev lo up
ip netns exec vrf1 brctl addbr bridge101
ip netns exec vrf1 brctl addif bridge101 vxlan101

This makes possible to separate not only layer 3 networks like VRF-lite networks.
Also, VRF netns based make possible to separate layer 2 networks on separate VRF
instances.

.. _bgp-cisco-compatibility:

Cisco Compatibility
Expand Down
1 change: 1 addition & 0 deletions include/linux/net_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
NETNSA_TARGET_NSID,
__NETNSA_MAX,
};

Expand Down
38 changes: 35 additions & 3 deletions lib/netns_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,20 @@ struct ns *ns_lookup(ns_id_t ns_id)
return ns_lookup_internal(ns_id);
}

void ns_walk_func(int (*func)(struct ns *))
void ns_walk_func(int (*func)(struct ns *,
void *param_in,
void **param_out),
void *param_in,
void **param_out)
{
struct ns *ns = NULL;
int ret;

RB_FOREACH (ns, ns_head, &ns_tree)
func(ns);
RB_FOREACH (ns, ns_head, &ns_tree) {
ret = func(ns, param_in, param_out);
if (ret == NS_WALK_STOP)
return;
}
}

const char *ns_get_name(struct ns *ns)
Expand Down Expand Up @@ -584,9 +592,33 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
return ret;
}

/* if relative link_nsid matches default netns,
* then return default absolute netns value
* otherwise, return NS_UNKNOWN
*/
ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
{
struct ns *ns;

ns = ns_lookup(ns_id_reference);
if (!ns)
return NS_UNKNOWN;
if (ns->relative_default_ns != link_nsid)
return NS_UNKNOWN;
ns = ns_get_default();
assert(ns);
return ns->ns_id;
}

ns_id_t ns_get_default_id(void)
{
if (default_ns)
return default_ns->ns_id;
return NS_DEFAULT_INTERNAL;
}

struct ns *ns_get_default(void)
{
return default_ns;
}

16 changes: 15 additions & 1 deletion lib/ns.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ struct ns {
/* Identifier, mapped on the NSID value */
ns_id_t internal_ns_id;

/* Identifier, value of NSID of default netns,
* relative value in that local netns
*/
ns_id_t relative_default_ns;

/* Name */
char *name;

Expand Down Expand Up @@ -120,7 +125,14 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id);
extern char *ns_netns_pathname(struct vty *vty, const char *name);

/* Parse and execute a function on all the NETNS */
extern void ns_walk_func(int (*func)(struct ns *));
#define NS_WALK_CONTINUE 0
#define NS_WALK_STOP 1

extern void ns_walk_func(int (*func)(struct ns *,
void *,
void **),
void *param_in,
void **param_out);

/* API to get the NETNS name, from the ns pointer */
extern const char *ns_get_name(struct ns *ns);
Expand Down Expand Up @@ -174,7 +186,9 @@ extern struct ns *ns_lookup_name(const char *name);
*/
extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
extern ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid);
extern void ns_disable(struct ns *ns);
extern struct ns *ns_get_default(void);

#ifdef __cplusplus
}
Expand Down
8 changes: 6 additions & 2 deletions lib/vrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
}

int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
ns_id_t ns_id, ns_id_t internal_ns_id)
ns_id_t ns_id, ns_id_t internal_ns_id,
ns_id_t rel_def_ns_id)
{
struct ns *ns = NULL;

Expand Down Expand Up @@ -700,6 +701,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
}
ns = ns_get_created(ns, pathname, ns_id);
ns->internal_ns_id = internal_ns_id;
ns->relative_default_ns = rel_def_ns_id;
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
Expand Down Expand Up @@ -797,7 +799,9 @@ DEFUN_NOSH (vrf_netns,

frr_with_privs(vrf_daemon_privs) {
ret = vrf_netns_handler_create(vty, vrf, pathname,
NS_UNKNOWN, NS_UNKNOWN);
NS_UNKNOWN,
NS_UNKNOWN,
NS_UNKNOWN);
}
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/vrf.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ extern int vrf_handler_create(struct vty *vty, const char *name,
*/
extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
char *pathname, ns_id_t ext_ns_id,
ns_id_t ns_id);
ns_id_t ns_id, ns_id_t rel_def_ns_id);

/* used internally to enable or disable VRF.
* Notify a change in the VRF ID of the VRF
Expand Down
46 changes: 39 additions & 7 deletions zebra/if_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
struct rtattr *attr[IFLA_VXLAN_MAX + 1];
vni_t vni_in_msg;
struct in_addr vtep_ip_in_msg;
ifindex_t ifindex_link;

memset(vxl_info, 0, sizeof(*vxl_info));
memset(attr, 0, sizeof(attr));
Expand Down Expand Up @@ -510,6 +511,15 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
*(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_GROUP]);
}

if (!attr[IFLA_VXLAN_LINK]) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldnt we return -1 in this case ? The caller of this function is not handling the returns values at this moment, but if this is an error condition it is better to return -1.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think. If I remember well,vxlan_link appears only when interface is moved to an other network namespace. that means that this flag will not be present when you create a vxlan interface with the link on the same network namespace. we don't have to notify any error here.

if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug("IFLA_VXLAN_LINK missing "
"from VXLAN IF message");
} else {
ifindex_link =
*(ifindex_t *)RTA_DATA(attr[IFLA_VXLAN_LINK]);
vxl_info->ifindex_link = ifindex_link;
}
return 0;
}

Expand All @@ -519,7 +529,8 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
* its members. Likewise, for VxLAN interface.
*/
static void netlink_interface_update_l2info(struct interface *ifp,
struct rtattr *link_data, int add)
struct rtattr *link_data, int add,
ns_id_t link_nsid)
{
if (!link_data)
return;
Expand All @@ -538,7 +549,12 @@ static void netlink_interface_update_l2info(struct interface *ifp,
struct zebra_l2info_vxlan vxlan_info;

netlink_extract_vxlan_info(link_data, &vxlan_info);
vxlan_info.link_nsid = link_nsid;
zebra_l2_vxlanif_add_update(ifp, &vxlan_info, add);
if (link_nsid != NS_UNKNOWN &&
vxlan_info.ifindex_link)
zebra_if_update_link(ifp, vxlan_info.ifindex_link,
link_nsid);
}
}

Expand Down Expand Up @@ -622,6 +638,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif;
ns_id_t link_nsid = ns_id;

zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
Expand Down Expand Up @@ -705,6 +722,11 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);

if (tb[IFLA_LINK_NETNSID]) {
link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
link_nsid = ns_id_get_absolute(ns_id, link_nsid);
}

/* Add interface.
* We add by index first because in some cases such as the master
* interface, we have the index before we have the name. Fixing
Expand Down Expand Up @@ -749,9 +771,10 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)

/* Extract and save L2 interface information, take additional actions.
*/
netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], 1);
netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA],
1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);
zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);

Expand Down Expand Up @@ -1168,6 +1191,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
uint8_t old_hw_addr[INTERFACE_HWADDR_MAX];
struct zebra_if *zif;
ns_id_t link_nsid = ns_id;

zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
Expand Down Expand Up @@ -1235,6 +1259,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);

if (tb[IFLA_LINK_NETNSID]) {
link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
link_nsid = ns_id_get_absolute(ns_id, link_nsid);
}
if (tb[IFLA_IFALIAS]) {
desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]);
}
Expand Down Expand Up @@ -1319,10 +1347,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Extract and save L2 interface information, take
* additional actions. */
netlink_interface_update_l2info(
ifp, linkinfo[IFLA_INFO_DATA], 1);
ifp, linkinfo[IFLA_INFO_DATA],
1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp,
bridge_ifindex);
bridge_ifindex,
ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
} else if (ifp->vrf_id != vrf_id) {
Expand Down Expand Up @@ -1421,10 +1451,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Extract and save L2 interface information, take
* additional actions. */
netlink_interface_update_l2info(
ifp, linkinfo[IFLA_INFO_DATA], 0);
ifp, linkinfo[IFLA_INFO_DATA],
0, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
zebra_l2if_update_bridge_slave(ifp,
bridge_ifindex);
bridge_ifindex,
ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
}
Expand Down
31 changes: 31 additions & 0 deletions zebra/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,23 @@ static void nbr_connected_dump_vty(struct vty *vty,
vty_out(vty, "\n");
}

static const char *zebra_zifslavetype_2str(zebra_slave_iftype_t zif_slave_type)
{
switch (zif_slave_type) {
case ZEBRA_IF_SLAVE_BRIDGE:
return "Bridge";
case ZEBRA_IF_SLAVE_VRF:
return "Vrf";
case ZEBRA_IF_SLAVE_BOND:
return "Bond";
case ZEBRA_IF_SLAVE_OTHER:
return "Other";
case ZEBRA_IF_SLAVE_NONE:
return "None";
}
return "None";
}

static const char *zebra_ziftype_2str(zebra_iftype_t zif_type)
{
switch (zif_type) {
Expand Down Expand Up @@ -1463,6 +1480,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)

vty_out(vty, " Interface Type %s\n",
zebra_ziftype_2str(zebra_if->zif_type));
vty_out(vty, " Interface Slave Type %s\n",
zebra_zifslavetype_2str(zebra_if->zif_slave_type));

if (IS_ZEBRA_IF_BRIDGE(ifp)) {
struct zebra_l2info_bridge *bridge_info;

Expand All @@ -1488,6 +1508,17 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
vty_out(vty, " Mcast Group %s",
inet_ntoa(vxlan_info->mcast_grp));
if (vxlan_info->ifindex_link &&
(vxlan_info->link_nsid != NS_UNKNOWN)) {
struct interface *ifp;

ifp = if_lookup_by_index_per_ns(
zebra_ns_lookup(vxlan_info->link_nsid),
vxlan_info->ifindex_link);
vty_out(vty, " Link Interface %s",
ifp == NULL ? "Unknown" :
ifp->name);
}
vty_out(vty, "\n");
}

Expand Down
Loading