2 * netconf_netlink.c - netconf interaction with the kernel using
4 * Copyright (C) 2021 Nvidia, Inc.
7 * This file is part of FRR.
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
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.
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
26 #ifdef HAVE_NETLINK /* Netlink OSes only */
30 #include "linux/netconf.h"
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"
38 static struct rtattr
*netconf_rta(struct netconfmsg
*ncm
)
40 return (struct rtattr
*)((char *)ncm
+
41 NLMSG_ALIGN(sizeof(struct netconfmsg
)));
45 * Handle netconf update about a single interface: create dplane
46 * context, and enqueue for processing in the main zebra pthread.
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
)
52 struct zebra_dplane_ctx
*ctx
;
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
);
59 dplane_ctx_set_netconf_mpls(ctx
, mpls_on
);
60 dplane_ctx_set_netconf_mcast(ctx
, mcast_on
);
62 /* Enqueue ctx for main pthread to process */
63 dplane_provider_enqueue_to_zebra(ctx
);
69 * Parse and process an incoming netlink netconf update.
71 int netlink_netconf_change(struct nlmsghdr
*h
, ns_id_t ns_id
, int startup
)
73 struct netconfmsg
*ncm
;
74 struct rtattr
*tb
[NETCONFA_MAX
+ 1] = {};
78 enum dplane_netconf_status_e mpls_on
= DPLANE_NETCONF_STATUS_UNKNOWN
;
79 enum dplane_netconf_status_e mcast_on
= DPLANE_NETCONF_STATUS_UNKNOWN
;
81 if (h
->nlmsg_type
!= RTM_NEWNETCONF
&& h
->nlmsg_type
!= RTM_DELNETCONF
)
84 len
= h
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct netconfmsg
));
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
)));
94 netlink_parse_rtattr(tb
, NETCONFA_MAX
, netconf_rta(ncm
), len
);
96 if (!tb
[NETCONFA_IFINDEX
]) {
97 zlog_err("NETCONF message received from netlink without an ifindex");
101 ifindex
= *(ifindex_t
*)RTA_DATA(tb
[NETCONFA_IFINDEX
]);
104 case NETCONFA_IFINDEX_ALL
:
105 case NETCONFA_IFINDEX_DEFAULT
:
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.
111 if (IS_ZEBRA_DEBUG_KERNEL
)
112 zlog_debug("%s: Ignoring global ifindex %d",
120 if (tb
[NETCONFA_INPUT
]) {
121 ival
= *(uint32_t *)RTA_DATA(tb
[NETCONFA_INPUT
]);
123 mpls_on
= DPLANE_NETCONF_STATUS_ENABLED
;
125 mpls_on
= DPLANE_NETCONF_STATUS_DISABLED
;
128 if (tb
[NETCONFA_MC_FORWARDING
]) {
129 ival
= *(uint32_t *)RTA_DATA(tb
[NETCONFA_MC_FORWARDING
]);
131 mcast_on
= DPLANE_NETCONF_STATUS_ENABLED
;
133 mcast_on
= DPLANE_NETCONF_STATUS_DISABLED
;
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
);
140 /* Create a dplane context and pass it along for processing */
141 netlink_netconf_dplane_update(ns_id
, ifindex
, mpls_on
, mcast_on
);
147 * Request info from the host OS. This only sends the request; any replies
148 * are processed asynchronously.
150 int netlink_request_netconf(int sockfd
)
155 struct netconfmsg ncm
;
159 nls
= kernel_netlink_nlsock_lookup(sockfd
);
161 if (IS_ZEBRA_DEBUG_KERNEL
)
162 zlog_debug("%s: nlsock %s", __func__
, nls
? nls
->name
: "NULL");
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
;
172 return netlink_request(nls
, &req
);
175 #endif /* HAVE_NETLINK */