From 4e851155f36d6dcea511dadb425e8b0996a89bd1 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Mon, 28 Jan 2019 16:07:00 +0100 Subject: [PATCH] ldpd, lib, zebra, topotests: add MPLS interface config from LDP When LDP is enabled per interface, MPLS is not turned on on each of those interfaces. Fix this by letting LDP configure the interface if the 'mpls auto' mode is configured. Create an IMSG to send interface config request from ldpe thread to main thread of ldp. Create a ZAPI message to set MPLS from ldp to zebra. Update the MPLS setting. Add a test that ensures that LDP properly configures the interface. Signed-off-by: Philippe Guibert --- ldpd/interface.c | 18 ++++++++ ldpd/ldp_zebra.c | 9 ++++ ldpd/ldpd.c | 10 +++++ ldpd/ldpd.h | 2 + ldpd/ldpe.h | 1 + lib/ldp_sync.h | 5 +++ lib/zclient.c | 46 +++++++++++++++++++++ lib/zclient.h | 7 ++++ tests/topotests/ldp_topo1/r1/zebra.conf | 1 + tests/topotests/ldp_topo1/r2/zebra.conf | 3 ++ tests/topotests/ldp_topo1/r3/zebra.conf | 2 + tests/topotests/ldp_topo1/r4/zebra.conf | 1 + tests/topotests/ldp_topo1/test_ldp_topo1.py | 32 ++++++++++++++ tests/topotests/lib/topogen.py | 6 ++- zebra/interface.c | 17 ++++++++ zebra/interface.h | 3 ++ zebra/zapi_msg.c | 1 + 17 files changed, 163 insertions(+), 1 deletion(-) diff --git a/ldpd/interface.c b/ldpd/interface.c index f0e70cbacce1..7208548e290a 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -8,6 +8,7 @@ */ #include +#include "privs.h" #include "ldpd.h" #include "ldpe.h" @@ -16,6 +17,8 @@ #include "sockopt.h" +extern struct zebra_privs_t ldpe_privs; + static __inline int iface_compare(const struct iface *, const struct iface *); static struct if_addr *if_addr_new(struct kaddr *); static struct if_addr *if_addr_lookup(struct if_addr_head *, struct kaddr *); @@ -93,6 +96,20 @@ ldpe_if_init(struct iface *iface) ldp_sync_fsm_init(iface, LDP_SYNC_STA_NOT_ACH); } +/* proc sys net mpls conf input set to 1 or 0 + * should be used from ldpe only + */ +void ldpe_interface_set_mpls(struct iface *iface, bool val) +{ + struct ldp_igp_configure_if_mpls config; + + config.ifindex = iface->ifindex; + config.status = val; + + ldpe_imsg_compose_parent(IMSG_LDP_CONFIGURE_IF_MPLS, getpid(), &config, + sizeof(config)); +} + void ldpe_if_exit(struct iface *iface) { @@ -277,6 +294,7 @@ if_start(struct iface *iface, int af) log_debug("%s: %s address-family %s", __func__, iface->name, af_name(af)); + ldpe_interface_set_mpls(iface, true); ia = iface_af_get(iface, af); gettimeofday(&now, NULL); diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index df682a1347be..8d2ca9f38546 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -124,6 +124,15 @@ ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *state) return 0; } +int ldp_sync_zebra_send_configure_if_mpls(struct ldp_igp_configure_if_mpls *config) +{ + if (zebra_send_interface_mpls_set(zclient, VRF_DEFAULT, config->ifindex, + config->status) <= 0) + return -1; + + return zclient_send_message(zclient); +} + static int ldp_sync_zebra_send_announce(void) { diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 3c616d4a8c8b..6e37bfe34157 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -602,6 +602,15 @@ static void main_dispatch_ldpe(struct event *thread) ldp_sync_zebra_send_state_update((struct ldp_igp_sync_if_state *)imsg.data); break; + case IMSG_LDP_CONFIGURE_IF_MPLS: + if (imsg.hdr.len != + IMSG_HEADER_SIZE + + sizeof(struct ldp_igp_configure_if_mpls)) + fatalx("IMSG_LDP_CONFIGURE_IF_MPLS imsg with wrong len"); + + ldp_sync_zebra_send_configure_if_mpls( + (struct ldp_igp_configure_if_mpls *)imsg.data); + break; default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -1519,6 +1528,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf) if (if_lookup_name(xconf, iface->name) == NULL) { switch (ldpd_process) { case PROC_LDP_ENGINE: + ldpe_interface_set_mpls(iface, false); ldpe_if_exit(iface); break; case PROC_LDE_ENGINE: diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 81c6ba3ccd57..33466293bdfb 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -151,6 +151,7 @@ enum imsg_type { IMSG_RLFA_UNREG_ALL, IMSG_RLFA_LABELS, IMSG_AGENTX_ENABLED, + IMSG_LDP_CONFIGURE_IF_MPLS, }; struct ldpd_init { @@ -890,6 +891,7 @@ extern char ctl_sock_path[MAXPATHLEN]; void ldp_zebra_init(struct event_loop *m); void ldp_zebra_destroy(void); int ldp_sync_zebra_send_state_update(struct ldp_igp_sync_if_state *); +int ldp_sync_zebra_send_configure_if_mpls(struct ldp_igp_configure_if_mpls *); int ldp_zebra_send_rlfa_labels(struct zapi_rlfa_response * rlfa_labels); diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index f310ba5dd209..7ba26de193db 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -306,6 +306,7 @@ void ldpe_l2vpn_init(struct l2vpn *); void ldpe_l2vpn_exit(struct l2vpn *); void ldpe_l2vpn_pw_init(struct l2vpn_pw *); void ldpe_l2vpn_pw_exit(struct l2vpn_pw *); +extern void ldpe_interface_set_mpls(struct iface *iface, bool val); DECLARE_HOOK(ldp_nbr_state_change, (struct nbr * nbr, int old_state), (nbr, old_state)); diff --git a/lib/ldp_sync.h b/lib/ldp_sync.h index 3a6ae5b3575a..85adb0870d32 100644 --- a/lib/ldp_sync.h +++ b/lib/ldp_sync.h @@ -56,6 +56,11 @@ struct ldp_igp_sync_if_state { bool sync_start; }; +struct ldp_igp_configure_if_mpls { + ifindex_t ifindex; + bool status; +}; + struct ldp_igp_sync_if_state_req { int proto; ifindex_t ifindex; diff --git a/lib/zclient.c b/lib/zclient.c index 1b2ff02f6137..4e582c773d22 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2864,6 +2864,52 @@ size_t zebra_interface_link_params_write(struct stream *s, return w; } +int zebra_send_interface_mpls_set(struct zclient *zclient, vrf_id_t vrf_id, + ifindex_t ifindex, bool set) +{ + struct stream *s; + int w; + + if (!zclient->obuf) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_INTERFACE_MPLS_SET, VRF_DEFAULT); + + w = stream_putl(s, ifindex); + w += stream_putc(s, set); + + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +struct interface *zebra_interface_mpls_set_read(struct stream *s, + vrf_id_t vrf_id, + bool *value_to_set) +{ + ifindex_t ifindex; + struct interface *ifp = NULL; + + STREAM_GETL(s, ifindex); + + ifp = if_lookup_by_index(ifindex, vrf_id); + + if (ifp == NULL) { + flog_err(EC_LIB_ZAPI_ENCODE, + "%s: unknown ifindex %u, shouldn't happen", __func__, + ifindex); + return NULL; + } + if (value_to_set) + STREAM_GETC(s, *value_to_set); + +stream_failure: + return ifp; +} + /* * format of message for address addition is: * 0 diff --git a/lib/zclient.h b/lib/zclient.h index 8b6aebc2fda8..43fa1a893376 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -133,6 +133,7 @@ typedef enum { ZEBRA_INTERFACE_DISABLE_RADV, ZEBRA_NEXTHOP_LOOKUP_MRIB, ZEBRA_INTERFACE_LINK_PARAMS, + ZEBRA_INTERFACE_MPLS_SET, ZEBRA_MPLS_LABELS_ADD, ZEBRA_MPLS_LABELS_DELETE, ZEBRA_MPLS_LABELS_REPLACE, @@ -1053,6 +1054,12 @@ extern struct interface *zebra_interface_link_params_read(struct stream *s, bool *changed); extern size_t zebra_interface_link_params_write(struct stream *, struct interface *); +extern int zebra_send_interface_mpls_set(struct zclient *zclient, + vrf_id_t vrf_id, ifindex_t ifindex, + bool set); +extern struct interface *zebra_interface_mpls_set_read(struct stream *s, + vrf_id_t vrf_id, + bool *value_to_set); extern enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient, uint8_t keep, uint32_t chunk_size, uint32_t base); diff --git a/tests/topotests/ldp_topo1/r1/zebra.conf b/tests/topotests/ldp_topo1/r1/zebra.conf index 55b4b0e9c656..877b93810347 100644 --- a/tests/topotests/ldp_topo1/r1/zebra.conf +++ b/tests/topotests/ldp_topo1/r1/zebra.conf @@ -9,6 +9,7 @@ interface r1-eth0 description to sw0 ip address 10.0.1.1/24 no link-detect + mpls auto ! ip forwarding ! diff --git a/tests/topotests/ldp_topo1/r2/zebra.conf b/tests/topotests/ldp_topo1/r2/zebra.conf index dd1dbac32b8a..688aece30e03 100644 --- a/tests/topotests/ldp_topo1/r2/zebra.conf +++ b/tests/topotests/ldp_topo1/r2/zebra.conf @@ -9,16 +9,19 @@ interface r2-eth0 description to sw0 ip address 10.0.1.2/24 no link-detect + mpls auto ! interface r2-eth1 description to sw1 ip address 10.0.2.2/24 no link-detect + mpls auto ! interface r2-eth2 description to sw2 ip address 10.0.3.2/24 no link-detect + mpls auto ! ip forwarding ! diff --git a/tests/topotests/ldp_topo1/r3/zebra.conf b/tests/topotests/ldp_topo1/r3/zebra.conf index 456820fdb48a..dd76f9ea1468 100644 --- a/tests/topotests/ldp_topo1/r3/zebra.conf +++ b/tests/topotests/ldp_topo1/r3/zebra.conf @@ -9,11 +9,13 @@ interface r3-eth0 description to sw1 ip address 10.0.2.3/24 no link-detect + mpls auto ! interface r3-eth1 description to sw2 ip address 10.0.3.3/24 no link-detect + mpls auto ! ip forwarding ! diff --git a/tests/topotests/ldp_topo1/r4/zebra.conf b/tests/topotests/ldp_topo1/r4/zebra.conf index 4a270af578f6..149dc19b52b3 100644 --- a/tests/topotests/ldp_topo1/r4/zebra.conf +++ b/tests/topotests/ldp_topo1/r4/zebra.conf @@ -9,6 +9,7 @@ interface r4-eth0 description to sw1 ip address 10.0.2.4/24 no link-detect + mpls auto ! ip forwarding ! diff --git a/tests/topotests/ldp_topo1/test_ldp_topo1.py b/tests/topotests/ldp_topo1/test_ldp_topo1.py index fdd75581a3ec..eba2be424054 100644 --- a/tests/topotests/ldp_topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp_topo1/test_ldp_topo1.py @@ -134,6 +134,7 @@ def setup_module(module): tgen.start_topology() net = tgen.net + os.environ["TOPOTESTS_MPLS_AUTO"] = "1" # Starting Routers for i in range(1, 5): @@ -781,6 +782,37 @@ def test_linux_mpls_routes(): assert fatal_error == "", fatal_error +def _check_mpls_interface_set(rname, ifname, value): + tgen = get_topogen() + val = ( + tgen.net[rname] + .cmd_raises("sysctl -n " + "net.mpls.conf." + ifname + ".input") + .strip() + ) + assert ( + val == value + ), f"{rname}, interface {ifname} has MPLS flag set to {val}, unexpected" + + +def test_linux_mpls_interface_settings(): + global fatal_error + + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + + # Verify Linux Kernel MPLS settings + print("\n\n** Verifying Linux MPLS interface settings") + print("******************************************\n") + _check_mpls_interface_set("r1", "r1-eth0", "1") + _check_mpls_interface_set("r2", "r2-eth0", "1") + _check_mpls_interface_set("r2", "r2-eth1", "1") + _check_mpls_interface_set("r2", "r2-eth2", "1") + _check_mpls_interface_set("r3", "r3-eth0", "1") + _check_mpls_interface_set("r3", "r3-eth1", "1") + _check_mpls_interface_set("r4", "r4-eth0", "1") + + def test_shutdown_check_stderr(): global fatal_error net = get_topogen().net diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 7b06f3d127ed..ba5b4cccbd44 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -896,9 +896,13 @@ def start(self): daemon=daemon, ) + if nrouter.daemons["ldpd"] == 1 and not os.environ.get("TOPOTESTS_MPLS_AUTO"): + need_mpls_for_ldp = True + else: + need_mpls_for_ldp = False if result != "": self.tgen.set_error(result) - elif nrouter.daemons["ldpd"] == 1 or nrouter.daemons["pathd"] == 1: + elif need_mpls_for_ldp or nrouter.daemons["pathd"] == 1: # Enable MPLS processing on all interfaces. for interface in self.links: topotest.sysctl_assure( diff --git a/zebra/interface.c b/zebra/interface.c index 0b7cfc371355..8fc49a04b451 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -5397,6 +5397,23 @@ void mpls_interface_update(struct interface *ifp, uint8_t mpls) dplane_intf_mpls_modify_state(ifp, mpls); } +void zebra_interface_mpls_set(ZAPI_HANDLER_ARGS) +{ + struct interface *ifp; + bool mpls = false; + struct stream *s; + + s = msg; + ifp = zebra_interface_mpls_set_read(s, zvrf->vrf->vrf_id, &mpls); + if (!ifp) + return; + + if (mpls) + mpls_interface_update(ifp, IF_ZEBRA_DATA_ON); + else + mpls_interface_update(ifp, IF_ZEBRA_DATA_OFF); +} + static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp, const char *addr_str, const char *peer_str, const char *label) diff --git a/zebra/interface.h b/zebra/interface.h index deb14667823c..5ecf88b5336c 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -17,6 +17,7 @@ #include "zebra/zebra_nhg_private.h" #include "zebra/zebra_router.h" #include "zebra/rtadv.h" +#include "zebra/zserv.h" #ifdef __cplusplus extern "C" { @@ -338,6 +339,8 @@ extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); extern const char *zebra_protodown_rc_str(uint32_t protodown_rc, char *pd_buf, uint32_t pd_buf_len); extern void mpls_interface_update(struct interface *ifp, uint8_t mpls); +extern void zebra_interface_mpls_set(struct zserv *client, struct zmsghdr *hdr, + struct stream *msg, struct zebra_vrf *zvrf); void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx); extern void if_mpls_set_default(struct zebra_if *zif); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 2383f6aa8cdf..0c2d42aec750 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3887,6 +3887,7 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register, [ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable, [ZEBRA_INTERFACE_DISABLE_RADV] = zebra_interface_radv_disable, + [ZEBRA_INTERFACE_MPLS_SET] = zebra_interface_mpls_set, [ZEBRA_SR_POLICY_SET] = zread_sr_policy_set, [ZEBRA_SR_POLICY_DELETE] = zread_sr_policy_delete, [ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,