Merge pull request #7089 from pguibert6WIND/netns-refactor

Netns refactor
This commit is contained in:
Russ White 2020-09-18 11:02:30 -04:00 committed by GitHub
commit 0a6e6613d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 868 additions and 173 deletions

View File

@ -1144,7 +1144,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;
}

View File

@ -2540,6 +2540,26 @@ 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, it is necessary to set both bridge and vxlan interface
in 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 it 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-debugging:

View File

@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
NETNSA_TARGET_NSID,
__NETNSA_MAX,
};

View File

@ -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)
@ -584,9 +592,35 @@ 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;
}

View File

@ -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;
@ -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);
@ -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
}

View File

@ -659,7 +659,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;
@ -706,6 +707,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 */
@ -801,7 +803,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;
}

View File

@ -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

View File

View File

@ -0,0 +1,26 @@
debug bgp neighbor-events
debug bgp updates
debug bgp zebra
router bgp 65000
bgp router-id 192.168.100.21
bgp log-neighbor-changes
no bgp default ipv4-unicast
neighbor 192.168.100.41 remote-as 65000
neighbor 192.168.100.41 capability extended-nexthop
!
address-family l2vpn evpn
neighbor 192.168.100.41 activate
advertise-all-vni
exit-address-family
!
router bgp 65000 vrf r1-vrf-101
bgp router-id 192.168.102.21
bgp log-neighbor-changes
no bgp network import-check
address-family ipv4 unicast
network 192.168.102.21/32
exit-address-family
address-family l2vpn evpn
advertise ipv4 unicast
exit-address-family
!

View File

@ -0,0 +1,22 @@
log stdout
hostname r1
password zebra
debug zebra vxlan
debug zebra kernel
debug zebra dplane
debug zebra rib
log stdout
vrf r1-vrf-101
vni 101
exit-vrf
!
interface r1-eth0
ip address 192.168.100.21/24
!
interface loop101 vrf r1-vrf-101
ip address 192.168.102.21/32
!

View File

@ -0,0 +1,27 @@
debug bgp neighbor-events
debug bgp updates
debug bgp zebra
router bgp 65000
bgp router-id 192.168.100.41
bgp log-neighbor-changes
no bgp default ipv4-unicast
neighbor 192.168.100.21 peer-group
neighbor 192.168.100.21 remote-as 65000
neighbor 192.168.100.21 capability extended-nexthop
!
address-family l2vpn evpn
neighbor 192.168.100.21 activate
advertise-all-vni
exit-address-family
!
router bgp 65000 vrf r2-vrf-101
bgp router-id 192.168.101.41
bgp log-neighbor-changes
no bgp network import-check
address-family ipv4 unicast
network 192.168.101.41/32
exit-address-family
address-family l2vpn evpn
advertise ipv4 unicast
exit-address-family
!

View File

@ -0,0 +1,18 @@
log stdout
hostname r2
password zebra
debug zebra vxlan
vrf r2-vrf-101
vni 101
exit-vrf
!
interface loop101 vrf r2-vrf-101
ip address 192.168.101.41/32
!
interface r2-eth0
ip address 192.168.100.41/24
!

View File

@ -0,0 +1,234 @@
#!/usr/bin/env python
#
# test_bgp_evpn.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2019 by 6WIND
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_bgp_evpn.py: Test the FRR/Quagga BGP daemon with BGP IPv6 interface
with route advertisements on a separate netns.
"""
import os
import sys
import json
from functools import partial
import pytest
import platform
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, '../'))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
# Required to instantiate the topology builder class.
from mininet.topo import Topo
l3mdev_accept = 0
krel = ''
class BGPEVPNTopo(Topo):
"Test topology builder"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
tgen.add_router('r1')
tgen.add_router('r2')
switch = tgen.add_switch('s1')
switch.add_link(tgen.gears['r1'])
switch.add_link(tgen.gears['r2'])
switch = tgen.add_switch('s2')
switch.add_link(tgen.gears['r1'])
switch = tgen.add_switch('s3')
switch.add_link(tgen.gears['r2'])
def setup_module(mod):
"Sets up the pytest environment"
global l3mdev_accept
global krel
tgen = Topogen(BGPEVPNTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
krel = platform.release()
if topotest.version_cmp(krel, '4.18') < 0:
logger.info('BGP EVPN RT5 NETNS tests will not run (have kernel "{}", but it requires 4.18)'.format(krel))
return pytest.skip('Skipping BGP EVPN RT5 NETNS Test. Kernel not supported')
l3mdev_accept = 1
logger.info('setting net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept))
# create VRF vrf-101 on R1 and R2
# create loop101
cmds_vrflite = ['sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept),
'ip link add {}-vrf-101 type vrf table 101',
'ip ru add oif {}-vrf-101 table 101',
'ip ru add iif {}-vrf-101 table 101',
'ip link set dev {}-vrf-101 up',
'sysctl -w net.ipv4.tcp_l3mdev_accept={}'.format(l3mdev_accept),
'ip link add loop101 type dummy',
'ip link set dev loop101 master {}-vrf-101',
'ip link set dev loop101 up']
cmds_netns = ['ip netns add {}-vrf-101',
'ip link add loop101 type dummy',
'ip link set dev loop101 netns {}-vrf-101',
'ip netns exec {}-vrf-101 ip link set dev loop101 up']
cmds_r2 = [ # config routing 101
'ip link add name bridge-101 up type bridge stp_state 0',
'ip link set bridge-101 master {}-vrf-101',
'ip link set dev bridge-101 up',
'ip link add name vxlan-101 type vxlan id 101 dstport 4789 dev r2-eth0 local 192.168.100.41',
'ip link set dev vxlan-101 master bridge-101',
'ip link set vxlan-101 up type bridge_slave learning off flood off mcast_flood off']
cmds_r1_netns_method3 = ['ip link add name vxlan-{1} type vxlan id {1} dstport 4789 dev {0}-eth0 local 192.168.100.21',
'ip link set dev vxlan-{1} netns {0}-vrf-{1}',
'ip netns exec {0}-vrf-{1} ip li set dev lo up',
'ip netns exec {0}-vrf-{1} ip link add name bridge-{1} up type bridge stp_state 0',
'ip netns exec {0}-vrf-{1} ip link set dev vxlan-{1} master bridge-{1}',
'ip netns exec {0}-vrf-{1} ip link set bridge-{1} up',
'ip netns exec {0}-vrf-{1} ip link set vxlan-{1} up']
router = tgen.gears['r1']
for cmd in cmds_netns:
logger.info('cmd to r1: '+cmd);
output = router.run(cmd.format('r1'))
logger.info('result: '+output);
router = tgen.gears['r2']
for cmd in cmds_vrflite:
logger.info('cmd to r2: '+cmd.format('r2'));
output = router.run(cmd.format('r2'))
logger.info('result: '+output);
for cmd in cmds_r2:
logger.info('cmd to r2: '+cmd.format('r2'));
output = router.run(cmd.format('r2'))
logger.info('result: '+output);
router = tgen.gears['r1']
bridge_id = '101'
for cmd in cmds_r1_netns_method3:
logger.info('cmd to r1: '+cmd.format('r1', bridge_id));
output = router.run(cmd.format('r1', bridge_id))
logger.info('result: '+output);
router = tgen.gears['r1']
for rname, router in router_list.iteritems():
if rname == 'r1':
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname)),
'--vrfwnetns -o vrf0'
)
else:
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
)
router.load_config(
TopoRouter.RD_BGP,
os.path.join(CWD, '{}/bgpd.conf'.format(rname))
)
# Initialize all routers.
tgen.start_router()
def teardown_module(_mod):
"Teardown the pytest environment"
tgen = get_topogen()
cmds_rx_netns = ['ip netns del {}-vrf-101']
router = tgen.gears['r1']
for cmd in cmds_rx_netns:
logger.info('cmd to r1: '+cmd.format('r1'));
output = router.run(cmd.format('r1'))
tgen.stop_topology()
def test_protocols_convergence():
"""
Assert that all protocols have converged
statuses as they depend on it.
"""
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
topotest.sleep(4, 'waiting 4 seconds for bgp convergence')
# Check IPv4/IPv6 routing tables.
output = tgen.gears['r1'].vtysh_cmd('show bgp l2vpn evpn', isjson=False)
logger.info('==== result from show bgp l2vpn evpn')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show bgp l2vpn evpn route detail', isjson=False)
logger.info('==== result from show bgp l2vpn evpn route detail')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show bgp vrf r1-vrf-101 ipv4', isjson=False)
logger.info('==== result from show bgp vrf r1-vrf-101 ipv4')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show bgp vrf r1-vrf-101', isjson=False)
logger.info('==== result from show bgp vrf r1-vrf-101 ')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show ip route vrf r1-vrf-101', isjson=False)
logger.info('==== result from show ip route vrf r1-vrf-101')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show evpn vni detail', isjson=False)
logger.info('==== result from show evpn vni detail')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show evpn next-hops vni all', isjson=False)
logger.info('==== result from show evpn next-hops vni all')
logger.info(output)
output = tgen.gears['r1'].vtysh_cmd('show evpn rmac vni all', isjson=False)
logger.info('==== result from show evpn next-hops vni all')
logger.info(output)
# Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn)
pingrouter = tgen.gears['r1']
logger.info('Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)')
output = pingrouter.run('ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000')
logger.info(output)
if '1000 packets transmitted, 1000 received' not in output:
assertmsg = 'expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok'
assert 0, assertmsg
else:
logger.info('Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK')
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip('Memory leak test/report is disabled')
tgen.report_memory_leaks()
if __name__ == '__main__':
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -798,8 +798,10 @@ 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])
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
@ -848,7 +850,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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);
@ -1349,9 +1351,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])
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]);
}
@ -1439,7 +1442,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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) {
@ -1540,7 +1544,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
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);
}

View File

@ -1242,6 +1242,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) {
@ -1469,6 +1486,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;

View File

@ -183,7 +183,7 @@ static void sigint(void)
vrf_terminate();
rtadv_terminate();
ns_walk_func(zebra_ns_early_shutdown);
ns_walk_func(zebra_ns_early_shutdown, NULL, NULL);
zebra_ns_notify_close();
access_list_reset();
@ -214,7 +214,7 @@ int zebra_finalize(struct thread *dummy)
zlog_info("Zebra final shutdown");
/* Final shutdown of ns resources */
ns_walk_func(zebra_ns_final_shutdown);
ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();

View File

@ -622,32 +622,31 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
return;
}
/*
* Map port or (port, VLAN) to an EVPN. This is invoked upon getting MAC
* notifications, to see if they are of interest.
*/
zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
static int zebra_evpn_map_vlan_ns(struct ns *ns,
void *_in_param,
void **_p_zevpn)
{
struct zebra_ns *zns;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if;
zebra_evpn_t **p_zevpn = (zebra_evpn_t **)_p_zevpn;
zebra_evpn_t *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
struct zebra_l2info_vxlan *vxl = NULL;
uint8_t bridge_vlan_aware;
zebra_evpn_t *zevpn;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
int found = 0;
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
if (!in_param)
return NS_WALK_STOP;
br_if = in_param->br_if;
zif = in_param->zif;
assert(zif);
br = &zif->l2info.br;
bridge_vlan_aware = br->vlan_aware;
assert(br_if);
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
@ -662,17 +661,101 @@ zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
if (zif->brslave_info.br_if != br_if)
continue;
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
if (!in_param->bridge_vlan_aware
|| vxl->access_vlan == in_param->vid) {
found = 1;
break;
}
}
if (!found)
return NS_WALK_CONTINUE;
zevpn = zebra_evpn_lookup(vxl->vni);
if (p_zevpn)
*p_zevpn = zevpn;
return NS_WALK_STOP;
}
/*
* Map port or (port, VLAN) to an EVPN. This is invoked upon getting MAC
* notifications, to see if they are of interest.
*/
zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
zebra_evpn_t **p_zevpn;
zebra_evpn_t *zevpn = NULL;
struct zebra_from_svi_param in_param;
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
in_param.bridge_vlan_aware = br->vlan_aware;
in_param.vid = vid;
in_param.br_if = br_if;
in_param.zif = zif;
p_zevpn = &zevpn;
ns_walk_func(zebra_evpn_map_vlan_ns,
(void *)&in_param,
(void **)p_zevpn);
return zevpn;
}
static int zebra_evpn_from_svi_ns(struct ns *ns,
void *_in_param,
void **_p_zevpn)
{
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *br_if;
zebra_evpn_t **p_zevpn = (zebra_evpn_t **)_p_zevpn;
zebra_evpn_t *zevpn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_vxlan *vxl = NULL;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
int found = 0;
if (!in_param)
return NS_WALK_STOP;
br_if = in_param->br_if;
zif = in_param->zif;
assert(zif);
/* TODO: Optimize with a hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
if (!if_is_operative(tmp_if))
continue;
vxl = &zif->l2info.vxl;
if (zif->brslave_info.br_if != br_if)
continue;
if (!in_param->bridge_vlan_aware
|| vxl->access_vlan == in_param->vid) {
found = 1;
break;
}
}
if (!found)
return NULL;
return NS_WALK_CONTINUE;
zevpn = zebra_evpn_lookup(vxl->vni);
return zevpn;
if (p_zevpn)
*p_zevpn = zevpn;
return NS_WALK_STOP;
}
/*
@ -682,16 +765,11 @@ zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
struct interface *br_if)
{
struct zebra_ns *zns;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
struct zebra_l2info_vxlan *vxl = NULL;
uint8_t bridge_vlan_aware;
vlanid_t vid = 0;
zebra_evpn_t *zevpn;
int found = 0;
zebra_evpn_t *zevpn = NULL;
zebra_evpn_t **p_zevpn;
struct zebra_if *zif;
struct zebra_from_svi_param in_param;
if (!br_if)
return NULL;
@ -704,8 +782,10 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
bridge_vlan_aware = br->vlan_aware;
if (bridge_vlan_aware) {
in_param.bridge_vlan_aware = br->vlan_aware;
in_param.vid = 0;
if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
if (!IS_ZEBRA_IF_VLAN(ifp))
@ -714,37 +794,52 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
zif = ifp->info;
assert(zif);
vl = &zif->l2info.vl;
vid = vl->vid;
in_param.vid = vl->vid;
}
in_param.br_if = br_if;
in_param.zif = zif;
p_zevpn = &zevpn;
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
ns_walk_func(zebra_evpn_from_svi_ns, (void *)&in_param,
(void **)p_zevpn);
return zevpn;
}
static int zvni_map_to_macvlan_ns(struct ns *ns,
void *_in_param,
void **_p_ifp)
{
struct zebra_ns *zns = ns->info;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
struct interface **p_ifp = (struct interface **)_p_ifp;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
if (!in_param)
return NS_WALK_STOP;
/* Identify corresponding VLAN interface. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
continue;
if (!if_is_operative(tmp_if))
continue;
vxl = &zif->l2info.vxl;
if (zif->brslave_info.br_if != br_if)
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
continue;
if (!bridge_vlan_aware || vxl->access_vlan == vid) {
found = 1;
break;
if (zif->link == in_param->svi_if) {
if (p_ifp)
*p_ifp = tmp_if;
return NS_WALK_STOP;
}
}
if (!found)
return NULL;
zevpn = zebra_evpn_lookup(vxl->vni);
return zevpn;
return NS_WALK_CONTINUE;
}
/* Map to MAC-VLAN interface corresponding to specified SVI interface.
@ -752,11 +847,10 @@ zebra_evpn_t *zebra_evpn_from_svi(struct interface *ifp,
struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
struct interface *svi_if)
{
struct zebra_ns *zns;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
int found = 0;
struct interface **p_ifp;
struct zebra_from_svi_param in_param;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
@ -771,25 +865,17 @@ struct interface *zebra_evpn_map_to_macvlan(struct interface *br_if,
zif = br_if->info;
assert(zif);
in_param.vid = 0;
in_param.br_if = br_if;
in_param.zif = NULL;
in_param.svi_if = svi_if;
p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
continue;
if (zif->link == svi_if) {
found = 1;
break;
}
}
return found ? tmp_if : NULL;
ns_walk_func(zvni_map_to_macvlan_ns,
(void *)&in_param,
(void **)p_ifp);
return tmp_if;
}
/*
@ -812,6 +898,7 @@ void zebra_evpn_install_mac_hash(struct hash_bucket *bucket, void *ctxt)
void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
{
struct zebra_ns *zns;
struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
struct zebra_l2info_vxlan *vxl;
@ -819,7 +906,10 @@ void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp)
zif = ifp->info;
vxl = &zif->l2info.vxl;
zns = zebra_ns_lookup(NS_DEFAULT);
zvrf = zebra_vrf_lookup_by_id(zevpn->vrf_id);
if (!zvrf || !zvrf->zns)
return;
zns = zvrf->zns;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@ -1315,7 +1405,7 @@ void process_remote_macip_add(vni_t vni, struct ethaddr *macaddr,
}
}
zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;

View File

@ -123,6 +123,15 @@ struct zebra_evpn_t_ {
struct list *local_es_evi_list;
};
/* for parsing evpn and vni contexts */
struct zebra_from_svi_param {
struct interface *br_if;
struct interface *svi_if;
struct zebra_if *zif;
uint8_t bridge_vlan_aware;
vlanid_t vid;
};
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if);
static inline struct interface *zevpn_map_to_svi(zebra_evpn_t *zevpn)

View File

@ -249,7 +249,7 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
struct zebra_ns *zns;
*vid = mac->fwd_info.local.vid;
zns = zebra_ns_lookup(NS_DEFAULT);
zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
*ifpP = if_lookup_by_index_per_ns(zns,
mac->fwd_info.local.ifindex);
}
@ -1610,6 +1610,12 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
{
struct zebra_if *zif = ifp->info;
bool es_change;
ns_id_t local_ns_id = NS_DEFAULT;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (zvrf && zvrf->zns)
local_ns_id = zvrf->zns->ns_id;
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
@ -1618,6 +1624,7 @@ static bool zebra_evpn_local_mac_update_fwd_info(zebra_mac_t *mac,
if (!mac->es) {
/* if es is set fwd_info is not-relevant/taped-out */
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
}
@ -2206,6 +2213,12 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
{
char buf[ETHER_ADDR_STRLEN];
zebra_mac_t *mac;
ns_id_t local_ns_id = NS_DEFAULT;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (zvrf && zvrf->zns)
local_ns_id = zvrf->zns->ns_id;
mac = zebra_evpn_mac_lookup(zevpn, macaddr);
if (!mac) {
@ -2225,6 +2238,7 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn,
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vlan_id;
*macp = mac;

View File

@ -91,6 +91,7 @@ struct zebra_mac_t_ {
union {
struct {
ifindex_t ifindex;
ns_id_t ns_id;
vlanid_t vid;
} local;

View File

@ -54,7 +54,13 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
{
struct vrf *vrf;
struct interface *ifp;
struct zebra_vrf *zvrf;
struct zebra_ns *zns;
zvrf = zebra_vrf_lookup_by_id(br_if->vrf_id);
assert(zvrf);
zns = zvrf->zns;
assert(zns);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES (vrf, ifp) {
struct zebra_if *zif;
@ -73,7 +79,8 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
br_slave = &zif->brslave_info;
if (link) {
if (br_slave->bridge_ifindex == br_if->ifindex)
if (br_slave->bridge_ifindex == br_if->ifindex &&
br_slave->ns_id == zns->ns_id)
br_slave->br_if = br_if;
} else {
if (br_slave->br_if == br_if)
@ -84,12 +91,14 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
}
/* Public functions */
void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave)
void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
struct zebra_ns *zns)
{
struct interface *br_if;
/* TODO: Handle change of master */
br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
assert(zns);
br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(zns->ns_id),
br_slave->bridge_ifindex);
if (br_if)
br_slave->br_if = br_if;
@ -248,23 +257,32 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
* from a bridge before it can be mapped to another bridge.
*/
void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t bridge_ifindex)
ifindex_t bridge_ifindex,
ns_id_t ns_id)
{
struct zebra_if *zif;
ifindex_t old_bridge_ifindex;
ns_id_t old_ns_id;
struct zebra_vrf *zvrf;
zif = ifp->info;
assert(zif);
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
if (old_bridge_ifindex == bridge_ifindex)
zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
if (!zvrf)
return;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
old_ns_id = zif->brslave_info.ns_id;
if (old_bridge_ifindex == bridge_ifindex &&
old_ns_id == zif->brslave_info.ns_id)
return;
zif->brslave_info.ns_id = ns_id;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
/* Set up or remove link with master */
if (bridge_ifindex != IFINDEX_INTERNAL) {
zebra_l2_map_slave_to_bridge(&zif->brslave_info);
zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);

View File

@ -37,6 +37,7 @@ extern "C" {
struct zebra_l2info_brslave {
ifindex_t bridge_ifindex; /* Bridge Master */
struct interface *br_if; /* Pointer to master */
ns_id_t ns_id; /* network namespace where bridge is */
};
/* zebra L2 interface information - bridge interface */
@ -81,7 +82,8 @@ union zebra_l2if_info {
#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) ((zif)->l2info.br.vlan_aware == 1)
extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
struct zebra_ns *zns);
extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
extern void
@ -101,7 +103,8 @@ extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
vlanid_t access_vlan);
extern void zebra_l2_vxlanif_del(struct interface *ifp);
extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
ifindex_t bridge_ifindex);
ifindex_t bridge_ifindex,
ns_id_t ns_id);
extern void zebra_l2if_update_bond_slave(struct interface *ifp,
ifindex_t bond_ifindex);

View File

@ -159,27 +159,34 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
return ns_id;
}
ns_id_t zebra_ns_id_get(const char *netnspath)
/* fd_param = -1 is ignored.
* netnspath set to null is ignored.
* one of the 2 params is mandatory. netnspath is looked in priority
*/
ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param)
{
int ns_id = -1;
struct sockaddr_nl snl;
int fd, sock, ret;
int fd = -1, sock, ret;
unsigned int seq;
ns_id_t return_nsid = NS_UNKNOWN;
/* netns path check */
if (!netnspath)
if (!netnspath && fd_param == -1)
return NS_UNKNOWN;
fd = open(netnspath, O_RDONLY);
if (fd == -1)
return NS_UNKNOWN;
if (netnspath) {
fd = open(netnspath, O_RDONLY);
if (fd == -1)
return NS_UNKNOWN;
} else if (fd_param != -1)
fd = fd_param;
/* netlink socket */
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
flog_err_sys(EC_LIB_SOCKET, "netlink( %u) socket() error: %s",
sock, safe_strerror(errno));
close(fd);
if (fd_param == -1)
close(fd);
return NS_UNKNOWN;
}
memset(&snl, 0, sizeof(snl));
@ -192,7 +199,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) socket() bind error: %s", sock,
safe_strerror(errno));
close(sock);
close(fd);
if (fd_param == -1)
close(fd);
return NS_UNKNOWN;
}
@ -214,7 +222,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
close(fd);
if (fd_param == -1)
close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@ -258,7 +267,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) recvfrom() error 2 when reading: %s",
fd, safe_strerror(errno));
close(sock);
close(fd);
if (fd_param == -1)
close(fd);
if (errno == ENOTSUP) {
zlog_debug("NEWNSID locally generated");
return zebra_ns_id_get_fallback(netnspath);
@ -279,7 +289,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
close(fd);
if (fd_param == -1)
close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@ -310,16 +321,18 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
} while (len != 0 && ret == 0);
}
close(fd);
if (fd_param == -1)
close(fd);
close(sock);
return return_nsid;
}
#else
ns_id_t zebra_ns_id_get(const char *netnspath)
ns_id_t zebra_ns_id_get(const char *netnspath, int fd __attribute__ ((unused)))
{
return zebra_ns_id_get_fallback(netnspath);
}
#endif /* ! defined(HAVE_NETLINK) */
#ifdef HAVE_NETNS
@ -355,7 +368,7 @@ ns_id_t zebra_ns_id_get_default(void)
return NS_DEFAULT_INTERNAL;
}
close(fd);
return zebra_ns_id_get((char *)NS_DEFAULT_NAME);
return zebra_ns_id_get((char *)NS_DEFAULT_NAME, -1);
#else /* HAVE_NETNS */
return NS_DEFAULT_INTERNAL;
#endif /* !HAVE_NETNS */

View File

@ -24,7 +24,7 @@
extern "C" {
#endif
extern ns_id_t zebra_ns_id_get(const char *netnspath);
extern ns_id_t zebra_ns_id_get(const char *netnspath, int fd);
extern ns_id_t zebra_ns_id_get_default(void);
#ifdef __cplusplus

View File

@ -72,13 +72,14 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
char *netnspath = ns_netns_pathname(NULL, name);
struct vrf *vrf;
int ret;
ns_id_t ns_id, ns_id_external;
ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
struct ns *default_ns;
if (netnspath == NULL)
return;
frr_with_privs(&zserv_privs) {
ns_id = zebra_ns_id_get(netnspath);
ns_id = zebra_ns_id_get(netnspath, -1);
}
if (ns_id == NS_UNKNOWN)
return;
@ -97,9 +98,21 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
ns_map_nsid_with_external(ns_id, false);
return;
}
default_ns = ns_get_default();
/* force kernel ns_id creation in that new vrf */
frr_with_privs(&zserv_privs) {
ns_switch_to_netns(netnspath);
ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
ns_switchback_to_initial();
}
frr_with_privs(&zserv_privs) {
ret = vrf_netns_handler_create(NULL, vrf, netnspath,
ns_id_external, ns_id);
ns_id_external,
ns_id,
ns_id_relative);
}
if (ret != CMD_SUCCESS) {
flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,

View File

@ -153,20 +153,25 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
/* During zebra shutdown, do partial cleanup while the async dataplane
* is still running.
*/
int zebra_ns_early_shutdown(struct ns *ns)
int zebra_ns_early_shutdown(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
if (zns == NULL)
return 0;
return zebra_ns_disable_internal(zns, false);
zebra_ns_disable_internal(zns, false);
return NS_WALK_CONTINUE;
}
/* During zebra shutdown, do final cleanup
* after all dataplane work is complete.
*/
int zebra_ns_final_shutdown(struct ns *ns)
int zebra_ns_final_shutdown(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
@ -175,7 +180,7 @@ int zebra_ns_final_shutdown(struct ns *ns)
kernel_terminate(zns, true);
return 0;
return NS_WALK_CONTINUE;
}
int zebra_ns_init(const char *optional_default_name)
@ -183,12 +188,16 @@ int zebra_ns_init(const char *optional_default_name)
struct ns *default_ns;
ns_id_t ns_id;
ns_id_t ns_id_external;
struct ns *ns;
frr_with_privs(&zserv_privs) {
ns_id = zebra_ns_id_get_default();
}
ns_id_external = ns_map_nsid_with_external(ns_id, true);
ns_init_management(ns_id_external, ns_id);
ns = ns_get_default();
if (ns)
ns->relative_default_ns = ns_id;
default_ns = ns_lookup(ns_get_default_id());
if (!default_ns) {

View File

@ -67,9 +67,12 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
int zebra_ns_init(const char *optional_default_name);
int zebra_ns_enable(ns_id_t ns_id, void **info);
int zebra_ns_disabled(struct ns *ns);
int zebra_ns_early_shutdown(struct ns *ns);
int zebra_ns_final_shutdown(struct ns *ns);
int zebra_ns_early_shutdown(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)));
int zebra_ns_final_shutdown(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)));
int zebra_ns_config_write(struct vty *vty, struct ns *ns);
#ifdef __cplusplus

View File

@ -782,6 +782,43 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
vty_out(vty, "\n");
}
static int zvni_map_to_svi_ns(struct ns *ns,
void *_in_param,
void **_p_ifp)
{
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct zebra_from_svi_param *in_param =
(struct zebra_from_svi_param *)_in_param;
struct zebra_l2info_vlan *vl;
struct interface *tmp_if = NULL;
struct interface **p_ifp = (struct interface **)_p_ifp;
struct zebra_if *zif;
if (!in_param)
return NS_WALK_STOP;
/* TODO: Optimize with a hash. */
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|| zif->link != in_param->br_if)
continue;
vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
if (vl->vid == in_param->vid) {
if (p_ifp)
*p_ifp = tmp_if;
return NS_WALK_STOP;
}
}
return NS_WALK_CONTINUE;
}
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
* of two cases:
* (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface
@ -791,15 +828,11 @@ static void zl3vni_print_hash_detail(struct hash_bucket *bucket, void *data)
*/
struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
struct zebra_ns *zns;
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
struct zebra_l2info_vlan *vl;
uint8_t bridge_vlan_aware;
int found = 0;
struct zebra_from_svi_param in_param;
struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
return NULL;
@ -808,33 +841,19 @@ struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
bridge_vlan_aware = br->vlan_aware;
in_param.bridge_vlan_aware = br->vlan_aware;
/* Check oper status of the SVI. */
if (!bridge_vlan_aware)
if (!in_param.bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
in_param.vid = vid;
in_param.br_if = br_if;
in_param.zif = NULL;
p_ifp = &tmp_if;
/* Identify corresponding VLAN interface. */
/* TODO: Optimize with a hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
if (!zif || zif->zif_type != ZEBRA_IF_VLAN
|| zif->link != br_if)
continue;
vl = &zif->l2info.vl;
if (vl->vid == vid) {
found = 1;
break;
}
}
return found ? tmp_if : NULL;
ns_walk_func(zvni_map_to_svi_ns, (void *)&in_param,
(void **)p_ifp);
return tmp_if;
}
static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn)
@ -846,18 +865,22 @@ static int zebra_evpn_vxlan_del(zebra_evpn_t *zevpn)
return zebra_evpn_del(zevpn);
}
/*
* Build the VNI hash table by going over the VxLAN interfaces. This
* is called when EVPN (advertise-all-vni) is enabled.
*/
static void zevpn_build_hash_table(void)
static int zevpn_build_hash_table_zns(struct ns *ns,
void *param_in __attribute__((unused)),
void **param_out __attribute__((unused)))
{
struct zebra_ns *zns;
struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *ifp;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return NS_WALK_STOP;
/* Walk VxLAN interfaces and create EVPN hash. */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
vni_t vni;
zebra_evpn_t *zevpn = NULL;
@ -874,7 +897,15 @@ static void zevpn_build_hash_table(void)
vxl = &zif->l2info.vxl;
vni = vxl->vni;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Intf %s(%u) VNI %u, link not in same "
"namespace than BGP EVPN core instance ",
ifp->name, ifp->ifindex, vni);
continue;
}
/* L3-VNI and L2-VNI are handled seperately */
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
@ -943,7 +974,7 @@ static void zevpn_build_hash_table(void)
zlog_debug(
"Failed to add EVPN hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
return;
return NS_WALK_CONTINUE;
}
if (zevpn->local_vtep_ip.s_addr !=
@ -985,6 +1016,19 @@ static void zevpn_build_hash_table(void)
}
}
}
return NS_WALK_CONTINUE;
}
/*
* Build the VNI hash table by going over the VxLAN interfaces. This
* is called when EVPN (advertise-all-vni) is enabled.
*/
static void zevpn_build_hash_table(void)
{
ns_walk_func(zevpn_build_hash_table_zns,
(void *)NULL,
(void **)NULL);
}
/*
@ -1617,14 +1661,22 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni)
return 0;
}
struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
void *_zl3vni,
void **_pifp)
{
struct zebra_ns *zns = NULL;
struct zebra_ns *zns = ns->info;
zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)_zl3vni;
struct route_node *rn = NULL;
struct interface *ifp = NULL;
struct zebra_vrf *zvrf;
zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return NS_WALK_STOP;
/* loop through all vxlan-interface */
zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
@ -1639,13 +1691,39 @@ struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
continue;
vxl = &zif->l2info.vxl;
if (vxl->vni == zl3vni->vni) {
zl3vni->local_vtep_ip = vxl->vtep_ip;
return ifp;
if (vxl->vni != zl3vni->vni)
continue;
/* link of VXLAN interface should be in zebra_evpn_vrf */
if (zvrf->zns->ns_id != vxl->link_nsid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
"Intf %s(%u) VNI %u, link not in same "
"namespace than BGP EVPN core instance ",
ifp->name, ifp->ifindex, vxl->vni);
continue;
}
zl3vni->local_vtep_ip = vxl->vtep_ip;
if (_pifp)
*_pifp = (void *)ifp;
return NS_WALK_STOP;
}
return NULL;
return NS_WALK_CONTINUE;
}
struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
{
struct interface **p_ifp;
struct interface *ifp = NULL;
p_ifp = &ifp;
ns_walk_func(zl3vni_map_to_vxlan_if_ns,
(void *)zl3vni, (void **)p_ifp);
return ifp;
}
struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
@ -3987,11 +4065,10 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
return -1;
}
zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id);
zvrf = zebra_vrf_get_evpn();
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(" No Vrf found for vrf_id: %d",
zevpn->vxlan_if->vrf_id);
zlog_debug(" No Evpn Global Vrf found");
return -1;
}
@ -5447,6 +5524,25 @@ stream_failure:
return;
}
static int macfdb_read_ns(struct ns *ns,
void *_in_param __attribute__((unused)),
void **out_param __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
macfdb_read(zns);
return NS_WALK_CONTINUE;
}
static int neigh_read_ns(struct ns *ns,
void *_in_param __attribute__((unused)),
void **out_param __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
neigh_read(zns);
return NS_WALK_CONTINUE;
}
/*
* Handle message from client to learn (or stop learning) about VNIs and MACs.
@ -5499,10 +5595,10 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
zebra_evpn_gw_macip_add_for_evpn_hash, NULL);
/* Read the MAC FDB */
macfdb_read(zvrf->zns);
ns_walk_func(macfdb_read_ns, NULL, NULL);
/* Read neighbors */
neigh_read(zvrf->zns);
ns_walk_func(neigh_read_ns, NULL, NULL);
} else {
/* Cleanup VTEPs for all EVPNs - uninstall from
* kernel and free entries.