]> git.proxmox.com Git - mirror_frr.git/blob - zebra/netconf_netlink.c
Merge pull request #8967 from anlancs/fix-startup-error-info
[mirror_frr.git] / zebra / netconf_netlink.c
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
32 #include "zebra/zebra_ns.h"
33 #include "zebra/zebra_dplane.h"
34 #include "zebra/kernel_netlink.h"
35 #include "zebra/netconf_netlink.h"
36 #include "zebra/debug.h"
37
38 static struct rtattr *netconf_rta(struct netconfmsg *ncm)
39 {
40 return (struct rtattr *)((char *)ncm +
41 NLMSG_ALIGN(sizeof(struct netconfmsg)));
42 }
43
44 /*
45 * Handle netconf update about a single interface: create dplane
46 * context, and enqueue for processing in the main zebra pthread.
47 */
48 static int netlink_netconf_dplane_update(ns_id_t ns_id, ifindex_t ifindex,
49 enum dplane_netconf_status_e mpls_on,
50 enum dplane_netconf_status_e mcast_on)
51 {
52 struct zebra_dplane_ctx *ctx;
53
54 ctx = dplane_ctx_alloc();
55 dplane_ctx_set_op(ctx, DPLANE_OP_INTF_NETCONFIG);
56 dplane_ctx_set_netconf_ns_id(ctx, ns_id);
57 dplane_ctx_set_netconf_ifindex(ctx, ifindex);
58
59 dplane_ctx_set_netconf_mpls(ctx, mpls_on);
60 dplane_ctx_set_netconf_mcast(ctx, mcast_on);
61
62 /* Enqueue ctx for main pthread to process */
63 dplane_provider_enqueue_to_zebra(ctx);
64
65 return 0;
66 }
67
68 /*
69 * Parse and process an incoming netlink netconf update.
70 */
71 int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
72 {
73 struct netconfmsg *ncm;
74 struct rtattr *tb[NETCONFA_MAX + 1] = {};
75 int len;
76 ifindex_t ifindex;
77 uint32_t ival;
78 enum dplane_netconf_status_e mpls_on = DPLANE_NETCONF_STATUS_UNKNOWN;
79 enum dplane_netconf_status_e mcast_on = DPLANE_NETCONF_STATUS_UNKNOWN;
80
81 if (h->nlmsg_type != RTM_NEWNETCONF && h->nlmsg_type != RTM_DELNETCONF)
82 return 0;
83
84 len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct netconfmsg));
85 if (len < 0) {
86 zlog_err("%s: Message received from netlink is of a broken size: %d, min %zu",
87 __func__, h->nlmsg_len,
88 (size_t)NLMSG_LENGTH(sizeof(struct netconfmsg)));
89 return -1;
90 }
91
92 ncm = NLMSG_DATA(h);
93
94 netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
95
96 if (!tb[NETCONFA_IFINDEX]) {
97 zlog_err("NETCONF message received from netlink without an ifindex");
98 return 0;
99 }
100
101 ifindex = *(ifindex_t *)RTA_DATA(tb[NETCONFA_IFINDEX]);
102
103 switch (ifindex) {
104 case NETCONFA_IFINDEX_ALL:
105 case NETCONFA_IFINDEX_DEFAULT:
106 /*
107 * We need the ability to handle netlink messages intended
108 * for all and default interfaces. I am not 100% sure
109 * what that is yet, or where we would store it.
110 */
111 if (IS_ZEBRA_DEBUG_KERNEL)
112 zlog_debug("%s: Ignoring global ifindex %d",
113 __func__, ifindex);
114
115 return 0;
116 default:
117 break;
118 }
119
120 if (tb[NETCONFA_INPUT]) {
121 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_INPUT]);
122 if (ival != 0)
123 mpls_on = DPLANE_NETCONF_STATUS_ENABLED;
124 else
125 mpls_on = DPLANE_NETCONF_STATUS_DISABLED;
126 }
127
128 if (tb[NETCONFA_MC_FORWARDING]) {
129 ival = *(uint32_t *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]);
130 if (ival != 0)
131 mcast_on = DPLANE_NETCONF_STATUS_ENABLED;
132 else
133 mcast_on = DPLANE_NETCONF_STATUS_DISABLED;
134 }
135
136 if (IS_ZEBRA_DEBUG_KERNEL)
137 zlog_debug("%s: interface %u is mpls on: %d multicast on: %d",
138 __func__, ifindex, mpls_on, mcast_on);
139
140 /* Create a dplane context and pass it along for processing */
141 netlink_netconf_dplane_update(ns_id, ifindex, mpls_on, mcast_on);
142
143 return 0;
144 }
145
146 /*
147 * Request info from the host OS. This only sends the request; any replies
148 * are processed asynchronously.
149 */
150 int netlink_request_netconf(int sockfd)
151 {
152 struct nlsock *nls;
153 struct {
154 struct nlmsghdr n;
155 struct netconfmsg ncm;
156 char buf[1024];
157 } req = {};
158
159 nls = kernel_netlink_nlsock_lookup(sockfd);
160
161 if (IS_ZEBRA_DEBUG_KERNEL)
162 zlog_debug("%s: nlsock %s", __func__, nls ? nls->name : "NULL");
163
164 if (nls == NULL)
165 return -1;
166
167 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct netconfmsg));
168 req.n.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
169 req.n.nlmsg_type = RTM_GETNETCONF;
170 req.ncm.ncm_family = AF_UNSPEC;
171
172 return netlink_request(nls, &req);
173 }
174
175 #endif /* HAVE_NETLINK */