summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2020-09-18 11:02:30 -0400
committerGitHub <noreply@github.com>2020-09-18 11:02:30 -0400
commit0a6e6613d73ccad69f749f689cc345973a8924fc (patch)
tree135ec46c8f951f6271edf44ad4173a1418acc58a
parent38281b61595a3eac33b6f0c3939257b2918567f2 (diff)
parentb0610ff7271eb72b69d50e6850ad9f3fb84dd62d (diff)
Merge pull request #7089 from pguibert6WIND/netns-refactor
Netns refactor
-rw-r--r--bgpd/bgp_zebra.c3
-rw-r--r--doc/user/bgp.rst20
-rw-r--r--include/linux/net_namespace.h1
-rw-r--r--lib/netns_linux.c40
-rw-r--r--lib/ns.h16
-rw-r--r--lib/vrf.c8
-rw-r--r--lib/vrf.h2
-rw-r--r--tests/topotests/bgp_evpn_rt5/__init__.py0
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/bgpd.conf26
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/zebra.conf22
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/bgpd.conf27
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/zebra.conf18
-rwxr-xr-xtests/topotests/bgp_evpn_rt5/test_bgp_evpn.py234
-rw-r--r--zebra/if_netlink.c17
-rw-r--r--zebra/interface.c20
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/zebra_evpn.c220
-rw-r--r--zebra/zebra_evpn.h9
-rw-r--r--zebra/zebra_evpn_mac.c16
-rw-r--r--zebra/zebra_evpn_mac.h1
-rw-r--r--zebra/zebra_l2.c32
-rw-r--r--zebra/zebra_l2.h7
-rw-r--r--zebra/zebra_netns_id.c43
-rw-r--r--zebra/zebra_netns_id.h2
-rw-r--r--zebra/zebra_netns_notify.c19
-rw-r--r--zebra/zebra_ns.c17
-rw-r--r--zebra/zebra_ns.h9
-rw-r--r--zebra/zebra_vxlan.c196
28 files changed, 862 insertions, 167 deletions
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index a1312b97b6..11e872f6b4 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -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;
}
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 427349c037..9983911581 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -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:
diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
index 0187c74d88..0ed9dd61d3 100644
--- a/include/linux/net_namespace.h
+++ b/include/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
+ NETNSA_TARGET_NSID,
__NETNSA_MAX,
};
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index 98f359401e..e8d549b4e0 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -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;
+}
+
diff --git a/lib/ns.h b/lib/ns.h
index 20e0a38e3b..286ff5b295 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -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
}
diff --git a/lib/vrf.c b/lib/vrf.c
index 6e4c983c66..cc7445558c 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -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;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index 83ed16b48e..a8514d74ed 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -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
diff --git a/tests/topotests/bgp_evpn_rt5/__init__.py b/tests/topotests/bgp_evpn_rt5/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/__init__.py
diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf
new file mode 100644
index 0000000000..9237682067
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf
@@ -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
+ !
diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
new file mode 100644
index 0000000000..f5eaab1953
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
@@ -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
+!
+
+
diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf
new file mode 100644
index 0000000000..6dcacd288d
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf
@@ -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
+ !
diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
new file mode 100644
index 0000000000..e5f962d254
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
@@ -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
+!
+
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
new file mode 100755
index 0000000000..69ef7e9fae
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -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))
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 5cd3e69299..90a08bbd6c 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -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);
}
diff --git a/zebra/interface.c b/zebra/interface.c
index b824e313ec..d29f61450e 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -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;
diff --git a/zebra/main.c b/zebra/main.c
index cfc45567d7..2afef46bb2 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -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();
diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c
index 653783f28c..56699c4e83 100644
--- a/zebra/zebra_evpn.c
+++ b/zebra/zebra_evpn.c
@@ -622,6 +622,60 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
return;
}
+static int zebra_evpn_map_vlan_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);
+ assert(br_if);
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* 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 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.
@@ -629,25 +683,51 @@ void zebra_evpn_svi_macip_del_for_evpn_hash(struct hash_bucket *bucket,
zebra_evpn_t *zebra_evpn_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
- 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;
- zebra_evpn_t *zevpn;
- int found = 0;
+ 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;
- bridge_vlan_aware = br->vlan_aware;
+ 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);
- /* 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 +742,20 @@ 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 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);
- /* 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;
+ in_param.vid = 0;
+ in_param.br_if = br_if;
+ in_param.zif = NULL;
+ in_param.svi_if = svi_if;
+ p_ifp = &tmp_if;
- if (zif->link == svi_if) {
- found = 1;
- break;
- }
- }
-
- return found ? tmp_if : NULL;
+ /* Identify corresponding VLAN interface. */
+ 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;
diff --git a/zebra/zebra_evpn.h b/zebra/zebra_evpn.h
index 3b6a5b21e8..27392ec85c 100644
--- a/zebra/zebra_evpn.h
+++ b/zebra/zebra_evpn.h
@@ -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)
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index eb4e4f9a57..75031ddba6 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -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;
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index 39aaf1fb30..f9ca81445f 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -91,6 +91,7 @@ struct zebra_mac_t_ {
union {
struct {
ifindex_t ifindex;
+ ns_id_t ns_id;
vlanid_t vid;
} local;
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index 1758c8f96a..417056ecb0 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -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);
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (!zvrf)
+ return;
+
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
- if (old_bridge_ifindex == 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);
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index 2735d915ec..f3b15c7770 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -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);
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 8de4daf439..79121bb086 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -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)
- return NS_UNKNOWN;
- fd = open(netnspath, O_RDONLY);
- if (fd == -1)
+ if (!netnspath && fd_param == -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 */
diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h
index 7a5f6851f4..dd9eab18e0 100644
--- a/zebra/zebra_netns_id.h
+++ b/zebra/zebra_netns_id.h
@@ -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
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index ec7681bf23..995fa6fb5a 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -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,
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 4e51437337..6462daf687 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -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) {
diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h
index dc79a83db0..f7d1f40782 100644
--- a/zebra/zebra_ns.h
+++ b/zebra/zebra_ns.h
@@ -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
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 13a58bc34a..61498973e9 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -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.