+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* netconf_netlink.c - netconf interaction with the kernel using
* netlink
* Copyright (C) 2021 Nvidia, Inc.
* Donald Sharp
- *
- * This file is part of FRR.
- *
- * FRR is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * FRR is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with FRR; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
*/
#include <zebra.h>
#include "linux/netconf.h"
+#include "lib/lib_errors.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_dplane.h"
#include "zebra/kernel_netlink.h"
* context, and enqueue for processing in the main zebra pthread.
*/
static int
-netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex,
+netlink_netconf_dplane_update(ns_id_t ns_id, afi_t afi, ifindex_t ifindex,
enum dplane_netconf_status_e mpls_on,
enum dplane_netconf_status_e mcast_on,
enum dplane_netconf_status_e linkdown_on)
ctx = dplane_ctx_alloc();
dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
dplane_ctx_set_ns_id(ctx, ns_id);
+ dplane_ctx_set_afi(ctx, afi);
dplane_ctx_set_ifindex(ctx, ifindex);
dplane_ctx_set_netconf_mpls(ctx, mpls_on);
int len;
ifindex_t ifindex;
uint32_t ival;
+ afi_t afi;
enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
enum dplane_netconf_status_e linkdown_on =
ncm = NLMSG_DATA(h);
+ /*
+ * FRR does not have an internal representation of afi_t for
+ * the MPLS Address Family that the kernel has. So let's
+ * just call it v4. This is ok because the kernel appears
+ * to do a good job of not sending data that is mixed/matched
+ * across families
+ */
+#ifdef AF_MPLS
+ if (ncm->ncm_family == AF_MPLS)
+ afi = AFI_IP;
+ else
+#endif /* AF_MPLS */
+ afi = family2afi(ncm->ncm_family);
+
netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
if (!tb[NETCONFA_IFINDEX]) {
ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
- switch (ifindex) {
- case NETCONFA_IFINDEX_ALL:
- case NETCONFA_IFINDEX_DEFAULT:
- /*
- * We need the ability to handle netlink messages intended
- * for all and default interfaces. I am not 100% sure
- * what that is yet, or where we would store it.
- */
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("%s: Ignoring global ifindex %d",
- __func__, ifindex);
-
- return 0;
- default:
- break;
- }
-
if (tb[NETCONFA_INPUT]) {
ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
if (ival != 0)
__func__, ifindex, mpls_on, mcast_on, linkdown_on);
/* Create a dplane context and pass it along for processing */
- netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on,
+ netlink_netconf_dplane_update(ns_id, afi, ifindex, mpls_on, mcast_on,
linkdown_on);
return 0;
return netlink_request(nls, &req);
}
+extern struct zebra_privs_t zserv_privs;
+/*
+ * Currently netconf has no ability to set from netlink.
+ * So we've received a request to do this work in the data plane.
+ * as such we need to set the value via the /proc system
+ */
+enum netlink_msg_status netlink_put_intf_netconfig(struct nl_batch *bth,
+ struct zebra_dplane_ctx *ctx)
+{
+ const char *ifname = dplane_ctx_get_ifname(ctx);
+ enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
+ char set[64];
+ char mpls_proc[PATH_MAX];
+ int fd, ret = FRR_NETLINK_ERROR;
+
+ snprintf(mpls_proc, sizeof(mpls_proc),
+ "/proc/sys/net/mpls/conf/%s/input", ifname);
+
+ if (mpls_on == DPLANE_NETCONF_STATUS_ENABLED)
+ snprintf(set, sizeof(set), "1\n");
+ else if (mpls_on == DPLANE_NETCONF_STATUS_DISABLED)
+ snprintf(set, sizeof(set), "0\n");
+ else {
+ flog_err_sys(
+ EC_LIB_DEVELOPMENT,
+ "%s: Expected interface %s to be set to ENABLED or DISABLED was %d",
+ __func__, ifname, mpls_on);
+ return ret;
+ }
+
+ frr_with_privs (&zserv_privs) {
+ fd = open(mpls_proc, O_WRONLY);
+ if (fd < 0) {
+ flog_err_sys(
+ EC_LIB_SOCKET,
+ "%s: Unable to open %s for writing: %s(%d)",
+ __func__, mpls_proc, safe_strerror(errno),
+ errno);
+ return ret;
+ }
+ if (write(fd, set, 2) == 2)
+ ret = FRR_NETLINK_SUCCESS;
+ else
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: Unsuccessful write to %s: %s(%d)",
+ __func__, mpls_proc, safe_strerror(errno),
+ errno);
+ close(fd);
+ }
+ return ret;
+}
+
#endif /* HAVE_NETLINK */