]> git.proxmox.com Git - mirror_frr.git/blame - zebra/netconf_netlink.c
Merge pull request #11842 from opensourcerouting/fix/topotests_platform_check
[mirror_frr.git] / zebra / netconf_netlink.c
CommitLineData
ebb61fca
DS
1/*
2 * netconf_netlink.c - netconf interaction with the kernel using
3 * netlink
4 * Copyright (C) 2021 Nvidia, Inc.
5 * Donald Sharp
6 *
7 * This file is part of FRR.
8 *
9 * FRR is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2, or (at your option) any
12 * later version.
13 *
14 * FRR is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with FRR; see the file COPYING. If not, write to the Free
21 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 * 02111-1307, USA.
23 */
24#include <zebra.h>
25
26#ifdef HAVE_NETLINK /* Netlink OSes only */
27
28#include <ns.h>
29
30#include "linux/netconf.h"
31
39ffa8e8 32#include "lib/lib_errors.h"
ebb61fca
DS
33#include "zebra/zebra_ns.h"
34#include "zebra/zebra_dplane.h"
35#include "zebra/kernel_netlink.h"
36#include "zebra/netconf_netlink.h"
37#include "zebra/debug.h"
38
39static struct rtattr *netconf_rta(struct netconfmsg *ncm)
40{
cd787a8a
MS
41 return (struct rtattr *)((char *)ncm +
42 NLMSG_ALIGN(sizeof(struct netconfmsg)));
ebb61fca
DS
43}
44
cd787a8a
MS
45/*
46 * Handle netconf update about a single interface: create dplane
47 * context, and enqueue for processing in the main zebra pthread.
48 */
3689905d 49static int
d53dc9bd 50netlink_netconf_dplane_update(ns_id_t ns_id, afi_t afi, ifindex_t ifindex,
3689905d
DS
51 enum dplane_netconf_status_e mpls_on,
52 enum dplane_netconf_status_e mcast_on,
53 enum dplane_netconf_status_e linkdown_on)
cd787a8a
MS
54{
55 struct zebra_dplane_ctx *ctx;
56
57 ctx = dplane_ctx_alloc();
58 dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
2b9dc841 59 dplane_ctx_set_ns_id(ctx, ns_id);
d53dc9bd 60 dplane_ctx_set_afi(ctx, afi);
2b9dc841 61 dplane_ctx_set_ifindex(ctx, ifindex);
cd787a8a
MS
62
63 dplane_ctx_set_netconf_mpls(ctx, mpls_on);
64 dplane_ctx_set_netconf_mcast(ctx, mcast_on);
3689905d 65 dplane_ctx_set_netconf_linkdown(ctx, linkdown_on);
cd787a8a
MS
66
67 /* Enqueue ctx for main pthread to process */
68 dplane_provider_enqueue_to_zebra(ctx);
69
70 return 0;
71}
72
73/*
74 * Parse and process an incoming netlink netconf update.
75 */
ebb61fca
DS
76int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
77{
78 struct netconfmsg *ncm;
79 struct rtattr *tb[NETCONFA_MAX + 1] = {};
80 int len;
81 ifindex_t ifindex;
cd787a8a 82 uint32_t ival;
d53dc9bd 83 afi_t afi;
cd787a8a
MS
84 enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
85 enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
3689905d
DS
86 enum dplane_netconf_status_e linkdown_on =
87 DPLANE_NETCONF_STATUS_UNKNOWN;
ebb61fca
DS
88
89 if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF)
90 return 0;
91
92 len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg));
93 if (len < 0) {
cd787a8a 94 zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu",
ebb61fca
DS
95 __func__, h->nlmsg_len,
96 (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg)));
97 return -1;
98 }
99
100 ncm = NLMSG_DATA(h);
101
d53dc9bd
DS
102 /*
103 * FRR does not have an internal representation of afi_t for
104 * the MPLS Address Family that the kernel has. So let's
105 * just call it v4. This is ok because the kernel appears
106 * to do a good job of not sending data that is mixed/matched
107 * across families
108 */
109 if (ncm->ncm_family == AF_MPLS)
110 afi = AFI_IP;
111 else
112 afi = family2afi(ncm->ncm_family);
113
ebb61fca
DS
114 netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
115
116 if (!tb[NETCONFA_IFINDEX]) {
cd787a8a 117 zlog_err("NETCONF message received from netlink without an ifindex");
ebb61fca
DS
118 return 0;
119 }
120
121 ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
122
ebb61fca 123 if (tb[NETCONFA_INPUT]) {
cd787a8a
MS
124 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
125 if (ival != 0)
126 mpls_on = DPLANE_NETCONF_STATUS_ENABLED;
127 else
128 mpls_on = DPLANE_NETCONF_STATUS_DISABLED;
ebb61fca
DS
129 }
130
131 if (tb[NETCONFA_MC_FORWARDING]) {
cd787a8a
MS
132 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]);
133 if (ival != 0)
134 mcast_on = DPLANE_NETCONF_STATUS_ENABLED;
135 else
136 mcast_on = DPLANE_NETCONF_STATUS_DISABLED;
ebb61fca
DS
137 }
138
3689905d
DS
139 if (tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]) {
140 ival = *(uint32_t *)RTA_DATA(
141 tb[NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN]);
142 if (ival != 0)
143 linkdown_on = DPLANE_NETCONF_STATUS_ENABLED;
144 else
145 linkdown_on = DPLANE_NETCONF_STATUS_DISABLED;
146 }
147
ebb61fca 148 if (IS_ZEBRA_DEBUG_KERNEL)
3689905d
DS
149 zlog_debug(
150 "%s: interface %u is mpls on: %d multicast on: %d linkdown: %d",
151 __func__, ifindex, mpls_on, mcast_on, linkdown_on);
cd787a8a
MS
152
153 /* Create a dplane context and pass it along for processing */
d53dc9bd 154 netlink_netconf_dplane_update(ns_id, afi, ifindex, mpls_on, mcast_on,
3689905d 155 linkdown_on);
ebb61fca
DS
156
157 return 0;
158}
159
cd787a8a
MS
160/*
161 * Request info from the host OS. This only sends the request; any replies
162 * are processed asynchronously.
163 */
164int netlink_request_netconf(int sockfd)
ebb61fca 165{
cd787a8a 166 struct nlsock *nls;
ebb61fca
DS
167 struct {
168 struct nlmsghdr n;
169 struct netconfmsg ncm;
170 char buf[1024];
cd787a8a
MS
171 } req = {};
172
173 nls = kernel_netlink_nlsock_lookup(sockfd);
174
175 if (IS_ZEBRA_DEBUG_KERNEL)
176 zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL");
177
178 if (nls == NULL)
179 return -1;
ebb61fca 180
ebb61fca
DS
181 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg));
182 req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
183 req.n.nlmsg_type = RTM_GETNETCONF;
184 req.ncm.ncm_family = AF_UNSPEC;
185
cd787a8a 186 return netlink_request(nls, &req);
ebb61fca
DS
187}
188
39ffa8e8
DS
189extern struct zebra_privs_t zserv_privs;
190/*
191 * Currently netconf has no ability to set from netlink.
192 * So we've received a request to do this work in the data plane.
193 * as such we need to set the value via the /proc system
194 */
195enum netlink_msg_status netlink_put_intf_netconfig(struct nl_batch *bth,
196 struct zebra_dplane_ctx *ctx)
197{
198 const char *ifname = dplane_ctx_get_ifname(ctx);
199 enum dplane_netconf_status_e mpls_on = dplane_ctx_get_netconf_mpls(ctx);
200 char set[64];
201 char mpls_proc[PATH_MAX];
202 int fd, ret = FRR_NETLINK_ERROR;
203
204 snprintf(mpls_proc, sizeof(mpls_proc),
205 "/proc/sys/net/mpls/conf/%s/input", ifname);
206
207 if (mpls_on == DPLANE_NETCONF_STATUS_ENABLED)
208 snprintf(set, sizeof(set), "1\n");
209 else if (mpls_on == DPLANE_NETCONF_STATUS_DISABLED)
210 snprintf(set, sizeof(set), "0\n");
211 else {
212 flog_err_sys(
213 EC_LIB_DEVELOPMENT,
214 "%s: Expected interface %s to be set to ENABLED or DISABLED was %d",
215 __func__, ifname, mpls_on);
216 return ret;
217 }
218
219 frr_with_privs (&zserv_privs) {
220 fd = open(mpls_proc, O_WRONLY);
221 if (fd < 0) {
222 flog_err_sys(
223 EC_LIB_SOCKET,
224 "%s: Unable to open %s for writing: %s(%d)",
225 __func__, mpls_proc, safe_strerror(errno),
226 errno);
227 return ret;
228 }
229 if (write(fd, set, 2) == 2)
230 ret = FRR_NETLINK_SUCCESS;
231 else
232 flog_err_sys(EC_LIB_SOCKET,
233 "%s: Unsuccessful write to %s: %s(%d)",
234 __func__, mpls_proc, safe_strerror(errno),
235 errno);
236 close(fd);
237 }
238 return ret;
239}
240
ebb61fca 241#endif /* HAVE_NETLINK */