Line data Source code
1 : /* Kernel routing table updates using netlink over GNU/Linux system.
2 : * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
3 : *
4 : * This file is part of GNU Zebra.
5 : *
6 : * GNU Zebra is free software; you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by the
8 : * Free Software Foundation; either version 2, or (at your option) any
9 : * later version.
10 : *
11 : * GNU Zebra is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License along
17 : * with this program; see the file COPYING; if not, write to the Free Software
18 : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : */
20 :
21 : #include <zebra.h>
22 :
23 : #ifdef HAVE_NETLINK
24 :
25 : /* The following definition is to workaround an issue in the Linux kernel
26 : * header files with redefinition of 'struct in6_addr' in both
27 : * netinet/in.h and linux/in6.h.
28 : * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html
29 : */
30 : #define _LINUX_IN6_H
31 :
32 : #include <net/if_arp.h>
33 : #include <linux/lwtunnel.h>
34 : #include <linux/mpls_iptunnel.h>
35 : #include <linux/seg6_iptunnel.h>
36 : #include <linux/seg6_local.h>
37 : #include <linux/neighbour.h>
38 : #include <linux/rtnetlink.h>
39 : #include <linux/nexthop.h>
40 :
41 : /* Hack for GNU libc version 2. */
42 : #ifndef MSG_TRUNC
43 : #define MSG_TRUNC 0x20
44 : #endif /* MSG_TRUNC */
45 :
46 : #include "linklist.h"
47 : #include "if.h"
48 : #include "log.h"
49 : #include "prefix.h"
50 : #include "plist.h"
51 : #include "plist_int.h"
52 : #include "connected.h"
53 : #include "table.h"
54 : #include "memory.h"
55 : #include "rib.h"
56 : #include "thread.h"
57 : #include "privs.h"
58 : #include "nexthop.h"
59 : #include "vrf.h"
60 : #include "vty.h"
61 : #include "mpls.h"
62 : #include "vxlan.h"
63 : #include "printfrr.h"
64 :
65 : #include "zebra/zapi_msg.h"
66 : #include "zebra/zebra_ns.h"
67 : #include "zebra/zebra_vrf.h"
68 : #include "zebra/rt.h"
69 : #include "zebra/redistribute.h"
70 : #include "zebra/interface.h"
71 : #include "zebra/debug.h"
72 : #include "zebra/rtadv.h"
73 : #include "zebra/zebra_ptm.h"
74 : #include "zebra/zebra_mpls.h"
75 : #include "zebra/kernel_netlink.h"
76 : #include "zebra/rt_netlink.h"
77 : #include "zebra/zebra_nhg.h"
78 : #include "zebra/zebra_mroute.h"
79 : #include "zebra/zebra_vxlan.h"
80 : #include "zebra/zebra_errors.h"
81 : #include "zebra/zebra_evpn_mh.h"
82 : #include "zebra/zebra_trace.h"
83 : #include "zebra/zebra_neigh.h"
84 :
85 : #ifndef AF_MPLS
86 : #define AF_MPLS 28
87 : #endif
88 :
89 : /* Re-defining as I am unable to include <linux/if_bridge.h> which has the
90 : * UAPI for MAC sync. */
91 : #ifndef _UAPI_LINUX_IF_BRIDGE_H
92 : #define BR_SPH_LIST_SIZE 10
93 : #endif
94 :
95 : static vlanid_t filter_vlan = 0;
96 :
97 : /* We capture whether the current kernel supports nexthop ids; by
98 : * default, we'll use them if possible. There's also a configuration
99 : * available to _disable_ use of kernel nexthops.
100 : */
101 : static bool supports_nh;
102 :
103 : struct gw_family_t {
104 : uint16_t filler;
105 : uint16_t family;
106 : union g_addr gate;
107 : };
108 :
109 : static const char ipv4_ll_buf[16] = "169.254.0.1";
110 : static struct in_addr ipv4_ll;
111 :
112 : /* Is this a ipv4 over ipv6 route? */
113 0 : static bool is_route_v4_over_v6(unsigned char rtm_family,
114 : enum nexthop_types_t nexthop_type)
115 : {
116 0 : if (rtm_family == AF_INET
117 0 : && (nexthop_type == NEXTHOP_TYPE_IPV6
118 0 : || nexthop_type == NEXTHOP_TYPE_IPV6_IFINDEX))
119 0 : return true;
120 :
121 : return false;
122 : }
123 :
124 : /* Helper to control use of kernel-level nexthop ids */
125 36 : static bool kernel_nexthops_supported(void)
126 : {
127 36 : return (supports_nh && !vrf_is_backend_netns()
128 72 : && zebra_nhg_kernel_nexthops_enabled());
129 : }
130 :
131 : /*
132 : * Some people may only want to use NHGs created by protos and not
133 : * implicitly created by Zebra. This check accounts for that.
134 : */
135 18 : static bool proto_nexthops_only(void)
136 : {
137 0 : return zebra_nhg_proto_nexthops_only();
138 : }
139 :
140 : /* Is this a proto created NHG? */
141 0 : static bool is_proto_nhg(uint32_t id, int type)
142 : {
143 : /* If type is available, use it as the source of truth */
144 0 : if (type) {
145 0 : if (type != ZEBRA_ROUTE_NHG)
146 : return true;
147 : return false;
148 : }
149 :
150 0 : if (id >= ZEBRA_NHG_PROTO_LOWER)
151 : return true;
152 :
153 : return false;
154 : }
155 :
156 : /*
157 : * The ipv4_ll data structure is used for all 5549
158 : * additions to the kernel. Let's figure out the
159 : * correct value one time instead for every
160 : * install/remove of a 5549 type route
161 : */
162 1 : void rt_netlink_init(void)
163 : {
164 1 : inet_pton(AF_INET, ipv4_ll_buf, &ipv4_ll);
165 1 : }
166 :
167 : /*
168 : * Mapping from dataplane neighbor flags to netlink flags
169 : */
170 0 : static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags)
171 : {
172 0 : uint8_t flags = 0;
173 :
174 0 : if (dplane_flags & DPLANE_NTF_EXT_LEARNED)
175 0 : flags |= NTF_EXT_LEARNED;
176 0 : if (dplane_flags & DPLANE_NTF_ROUTER)
177 0 : flags |= NTF_ROUTER;
178 0 : if (dplane_flags & DPLANE_NTF_USE)
179 0 : flags |= NTF_USE;
180 :
181 0 : return flags;
182 : }
183 :
184 : /*
185 : * Mapping from dataplane neighbor state to netlink state
186 : */
187 0 : static uint16_t neigh_state_to_netlink(uint16_t dplane_state)
188 : {
189 0 : uint16_t state = 0;
190 :
191 0 : if (dplane_state & DPLANE_NUD_REACHABLE)
192 0 : state |= NUD_REACHABLE;
193 0 : if (dplane_state & DPLANE_NUD_STALE)
194 0 : state |= NUD_STALE;
195 0 : if (dplane_state & DPLANE_NUD_NOARP)
196 0 : state |= NUD_NOARP;
197 0 : if (dplane_state & DPLANE_NUD_PROBE)
198 0 : state |= NUD_PROBE;
199 0 : if (dplane_state & DPLANE_NUD_INCOMPLETE)
200 0 : state |= NUD_INCOMPLETE;
201 0 : if (dplane_state & DPLANE_NUD_PERMANENT)
202 0 : state |= NUD_PERMANENT;
203 0 : if (dplane_state & DPLANE_NUD_FAILED)
204 0 : state |= NUD_FAILED;
205 :
206 0 : return state;
207 : }
208 :
209 :
210 0 : static inline bool is_selfroute(int proto)
211 : {
212 0 : if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF)
213 0 : || (proto == RTPROT_ZSTATIC) || (proto == RTPROT_ZEBRA)
214 0 : || (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG)
215 0 : || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
216 0 : || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
217 0 : || (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
218 0 : || (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)
219 0 : || (proto == RTPROT_SRTE)) {
220 0 : return true;
221 : }
222 :
223 : return false;
224 : }
225 :
226 11 : int zebra2proto(int proto)
227 : {
228 11 : switch (proto) {
229 : case ZEBRA_ROUTE_BABEL:
230 : proto = RTPROT_BABEL;
231 : break;
232 0 : case ZEBRA_ROUTE_BGP:
233 0 : proto = RTPROT_BGP;
234 0 : break;
235 0 : case ZEBRA_ROUTE_OSPF:
236 : case ZEBRA_ROUTE_OSPF6:
237 0 : proto = RTPROT_OSPF;
238 0 : break;
239 0 : case ZEBRA_ROUTE_STATIC:
240 0 : proto = RTPROT_ZSTATIC;
241 0 : break;
242 0 : case ZEBRA_ROUTE_ISIS:
243 0 : proto = RTPROT_ISIS;
244 0 : break;
245 0 : case ZEBRA_ROUTE_RIP:
246 0 : proto = RTPROT_RIP;
247 0 : break;
248 0 : case ZEBRA_ROUTE_RIPNG:
249 0 : proto = RTPROT_RIPNG;
250 0 : break;
251 0 : case ZEBRA_ROUTE_NHRP:
252 0 : proto = RTPROT_NHRP;
253 0 : break;
254 0 : case ZEBRA_ROUTE_EIGRP:
255 0 : proto = RTPROT_EIGRP;
256 0 : break;
257 0 : case ZEBRA_ROUTE_LDP:
258 0 : proto = RTPROT_LDP;
259 0 : break;
260 0 : case ZEBRA_ROUTE_SHARP:
261 0 : proto = RTPROT_SHARP;
262 0 : break;
263 0 : case ZEBRA_ROUTE_PBR:
264 0 : proto = RTPROT_PBR;
265 0 : break;
266 0 : case ZEBRA_ROUTE_OPENFABRIC:
267 0 : proto = RTPROT_OPENFABRIC;
268 0 : break;
269 0 : case ZEBRA_ROUTE_SRTE:
270 0 : proto = RTPROT_SRTE;
271 0 : break;
272 : case ZEBRA_ROUTE_TABLE:
273 : case ZEBRA_ROUTE_NHG:
274 11 : proto = RTPROT_ZEBRA;
275 : break;
276 0 : case ZEBRA_ROUTE_CONNECT:
277 : case ZEBRA_ROUTE_KERNEL:
278 0 : proto = RTPROT_KERNEL;
279 0 : break;
280 0 : default:
281 : /*
282 : * When a user adds a new protocol this will show up
283 : * to let them know to do something about it. This
284 : * is intentionally a warn because we should see
285 : * this as part of development of a new protocol
286 : */
287 0 : zlog_debug(
288 : "%s: Please add this protocol(%d) to proper rt_netlink.c handling",
289 : __func__, proto);
290 0 : proto = RTPROT_ZEBRA;
291 0 : break;
292 : }
293 :
294 11 : return proto;
295 : }
296 :
297 0 : static inline int proto2zebra(int proto, int family, bool is_nexthop)
298 : {
299 0 : switch (proto) {
300 : case RTPROT_BABEL:
301 : proto = ZEBRA_ROUTE_BABEL;
302 : break;
303 0 : case RTPROT_BGP:
304 0 : proto = ZEBRA_ROUTE_BGP;
305 0 : break;
306 0 : case RTPROT_OSPF:
307 0 : proto = (family == AF_INET) ? ZEBRA_ROUTE_OSPF
308 0 : : ZEBRA_ROUTE_OSPF6;
309 : break;
310 0 : case RTPROT_ISIS:
311 0 : proto = ZEBRA_ROUTE_ISIS;
312 0 : break;
313 0 : case RTPROT_RIP:
314 0 : proto = ZEBRA_ROUTE_RIP;
315 0 : break;
316 0 : case RTPROT_RIPNG:
317 0 : proto = ZEBRA_ROUTE_RIPNG;
318 0 : break;
319 0 : case RTPROT_NHRP:
320 0 : proto = ZEBRA_ROUTE_NHRP;
321 0 : break;
322 0 : case RTPROT_EIGRP:
323 0 : proto = ZEBRA_ROUTE_EIGRP;
324 0 : break;
325 0 : case RTPROT_LDP:
326 0 : proto = ZEBRA_ROUTE_LDP;
327 0 : break;
328 0 : case RTPROT_STATIC:
329 : case RTPROT_ZSTATIC:
330 0 : proto = ZEBRA_ROUTE_STATIC;
331 0 : break;
332 0 : case RTPROT_SHARP:
333 0 : proto = ZEBRA_ROUTE_SHARP;
334 0 : break;
335 0 : case RTPROT_PBR:
336 0 : proto = ZEBRA_ROUTE_PBR;
337 0 : break;
338 0 : case RTPROT_OPENFABRIC:
339 0 : proto = ZEBRA_ROUTE_OPENFABRIC;
340 0 : break;
341 0 : case RTPROT_SRTE:
342 0 : proto = ZEBRA_ROUTE_SRTE;
343 0 : break;
344 : case RTPROT_UNSPEC:
345 : case RTPROT_REDIRECT:
346 : case RTPROT_KERNEL:
347 : case RTPROT_BOOT:
348 : case RTPROT_GATED:
349 : case RTPROT_RA:
350 : case RTPROT_MRT:
351 : case RTPROT_BIRD:
352 : case RTPROT_DNROUTED:
353 : case RTPROT_XORP:
354 : case RTPROT_NTK:
355 : case RTPROT_MROUTED:
356 : case RTPROT_KEEPALIVED:
357 : case RTPROT_OPENR:
358 0 : proto = ZEBRA_ROUTE_KERNEL;
359 : break;
360 0 : case RTPROT_ZEBRA:
361 0 : if (is_nexthop) {
362 : proto = ZEBRA_ROUTE_NHG;
363 : break;
364 : }
365 : /* Intentional fall thru */
366 : default:
367 : /*
368 : * When a user adds a new protocol this will show up
369 : * to let them know to do something about it. This
370 : * is intentionally a warn because we should see
371 : * this as part of development of a new protocol
372 : */
373 0 : zlog_debug(
374 : "%s: Please add this protocol(%d) to proper rt_netlink.c handling",
375 : __func__, proto);
376 0 : proto = ZEBRA_ROUTE_KERNEL;
377 0 : break;
378 : }
379 0 : return proto;
380 : }
381 :
382 : /*
383 : Pending: create an efficient table_id (in a tree/hash) based lookup)
384 : */
385 0 : vrf_id_t vrf_lookup_by_table(uint32_t table_id, ns_id_t ns_id)
386 : {
387 0 : struct vrf *vrf;
388 0 : struct zebra_vrf *zvrf;
389 :
390 0 : RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
391 0 : zvrf = vrf->info;
392 0 : if (zvrf == NULL)
393 0 : continue;
394 : /* case vrf with netns : match the netnsid */
395 0 : if (vrf_is_backend_netns()) {
396 0 : if (ns_id == zvrf_id(zvrf))
397 0 : return zvrf_id(zvrf);
398 : } else {
399 : /* VRF is VRF_BACKEND_VRF_LITE */
400 0 : if (zvrf->table_id != table_id)
401 0 : continue;
402 0 : return zvrf_id(zvrf);
403 : }
404 : }
405 :
406 : return VRF_DEFAULT;
407 : }
408 :
409 : /**
410 : * @parse_encap_mpls() - Parses encapsulated mpls attributes
411 : * @tb: Pointer to rtattr to look for nested items in.
412 : * @labels: Pointer to store labels in.
413 : *
414 : * Return: Number of mpls labels found.
415 : */
416 0 : static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
417 : {
418 0 : struct rtattr *tb_encap[MPLS_IPTUNNEL_MAX + 1] = {0};
419 0 : mpls_lse_t *lses = NULL;
420 0 : int num_labels = 0;
421 0 : uint32_t ttl = 0;
422 0 : uint32_t bos = 0;
423 0 : uint32_t exp = 0;
424 0 : mpls_label_t label = 0;
425 :
426 0 : netlink_parse_rtattr_nested(tb_encap, MPLS_IPTUNNEL_MAX, tb);
427 0 : lses = (mpls_lse_t *)RTA_DATA(tb_encap[MPLS_IPTUNNEL_DST]);
428 0 : while (!bos && num_labels < MPLS_MAX_LABELS) {
429 0 : mpls_lse_decode(lses[num_labels], &label, &ttl, &exp, &bos);
430 0 : labels[num_labels++] = label;
431 : }
432 :
433 0 : return num_labels;
434 : }
435 :
436 : static enum seg6local_action_t
437 0 : parse_encap_seg6local(struct rtattr *tb,
438 : struct seg6local_context *ctx)
439 : {
440 0 : struct rtattr *tb_encap[SEG6_LOCAL_MAX + 1] = {};
441 0 : enum seg6local_action_t act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
442 :
443 0 : netlink_parse_rtattr_nested(tb_encap, SEG6_LOCAL_MAX, tb);
444 :
445 0 : if (tb_encap[SEG6_LOCAL_ACTION])
446 0 : act = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_ACTION]);
447 :
448 0 : if (tb_encap[SEG6_LOCAL_NH4])
449 0 : ctx->nh4 = *(struct in_addr *)RTA_DATA(
450 : tb_encap[SEG6_LOCAL_NH4]);
451 :
452 0 : if (tb_encap[SEG6_LOCAL_NH6])
453 0 : ctx->nh6 = *(struct in6_addr *)RTA_DATA(
454 : tb_encap[SEG6_LOCAL_NH6]);
455 :
456 0 : if (tb_encap[SEG6_LOCAL_TABLE])
457 0 : ctx->table = *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_TABLE]);
458 :
459 0 : if (tb_encap[SEG6_LOCAL_VRFTABLE])
460 0 : ctx->table =
461 : *(uint32_t *)RTA_DATA(tb_encap[SEG6_LOCAL_VRFTABLE]);
462 :
463 0 : return act;
464 : }
465 :
466 0 : static int parse_encap_seg6(struct rtattr *tb, struct in6_addr *segs)
467 : {
468 0 : struct rtattr *tb_encap[SEG6_IPTUNNEL_MAX + 1] = {};
469 0 : struct seg6_iptunnel_encap *ipt = NULL;
470 0 : struct in6_addr *segments = NULL;
471 :
472 0 : netlink_parse_rtattr_nested(tb_encap, SEG6_IPTUNNEL_MAX, tb);
473 :
474 : /*
475 : * TODO: It's not support multiple SID list.
476 : */
477 0 : if (tb_encap[SEG6_IPTUNNEL_SRH]) {
478 0 : ipt = (struct seg6_iptunnel_encap *)
479 : RTA_DATA(tb_encap[SEG6_IPTUNNEL_SRH]);
480 0 : segments = ipt->srh[0].segments;
481 0 : *segs = segments[0];
482 0 : return 1;
483 : }
484 :
485 : return 0;
486 : }
487 :
488 :
489 : static struct nexthop
490 0 : parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
491 : enum blackhole_type bh_type, int index, void *prefsrc,
492 : void *gate, afi_t afi, vrf_id_t vrf_id)
493 : {
494 0 : struct interface *ifp = NULL;
495 0 : struct nexthop nh = {0};
496 0 : mpls_label_t labels[MPLS_MAX_LABELS] = {0};
497 0 : int num_labels = 0;
498 0 : enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
499 0 : struct seg6local_context seg6l_ctx = {};
500 0 : struct in6_addr seg6_segs = {};
501 0 : int num_segs = 0;
502 :
503 0 : vrf_id_t nh_vrf_id = vrf_id;
504 0 : size_t sz = (afi == AFI_IP) ? 4 : 16;
505 :
506 0 : if (bh_type == BLACKHOLE_UNSPEC) {
507 0 : if (index && !gate)
508 0 : nh.type = NEXTHOP_TYPE_IFINDEX;
509 0 : else if (index && gate)
510 0 : nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4_IFINDEX
511 0 : : NEXTHOP_TYPE_IPV6_IFINDEX;
512 0 : else if (!index && gate)
513 0 : nh.type = (afi == AFI_IP) ? NEXTHOP_TYPE_IPV4
514 0 : : NEXTHOP_TYPE_IPV6;
515 : else {
516 0 : nh.type = NEXTHOP_TYPE_BLACKHOLE;
517 0 : nh.bh_type = bh_type;
518 : }
519 : } else {
520 0 : nh.type = NEXTHOP_TYPE_BLACKHOLE;
521 0 : nh.bh_type = bh_type;
522 : }
523 0 : nh.ifindex = index;
524 0 : if (prefsrc)
525 0 : memcpy(&nh.src, prefsrc, sz);
526 0 : if (gate)
527 0 : memcpy(&nh.gate, gate, sz);
528 :
529 0 : if (index) {
530 0 : ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index);
531 0 : if (ifp)
532 0 : nh_vrf_id = ifp->vrf->vrf_id;
533 : }
534 0 : nh.vrf_id = nh_vrf_id;
535 :
536 0 : if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
537 0 : && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
538 : == LWTUNNEL_ENCAP_MPLS) {
539 0 : num_labels = parse_encap_mpls(tb[RTA_ENCAP], labels);
540 : }
541 0 : if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
542 0 : && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
543 : == LWTUNNEL_ENCAP_SEG6_LOCAL) {
544 0 : seg6l_act = parse_encap_seg6local(tb[RTA_ENCAP], &seg6l_ctx);
545 : }
546 0 : if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
547 0 : && *(uint16_t *)RTA_DATA(tb[RTA_ENCAP_TYPE])
548 : == LWTUNNEL_ENCAP_SEG6) {
549 0 : num_segs = parse_encap_seg6(tb[RTA_ENCAP], &seg6_segs);
550 : }
551 :
552 0 : if (rtm->rtm_flags & RTNH_F_ONLINK)
553 0 : SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
554 :
555 0 : if (rtm->rtm_flags & RTNH_F_LINKDOWN)
556 0 : SET_FLAG(nh.flags, NEXTHOP_FLAG_LINKDOWN);
557 :
558 0 : if (num_labels)
559 0 : nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels, labels);
560 :
561 0 : if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
562 0 : nexthop_add_srv6_seg6local(&nh, seg6l_act, &seg6l_ctx);
563 :
564 0 : if (num_segs)
565 0 : nexthop_add_srv6_seg6(&nh, &seg6_segs);
566 :
567 0 : return nh;
568 : }
569 :
570 0 : static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
571 : struct nexthop_group *ng,
572 : struct rtmsg *rtm,
573 : struct rtnexthop *rtnh,
574 : struct rtattr **tb,
575 : void *prefsrc, vrf_id_t vrf_id)
576 : {
577 0 : void *gate = NULL;
578 0 : struct interface *ifp = NULL;
579 0 : int index = 0;
580 : /* MPLS labels */
581 0 : mpls_label_t labels[MPLS_MAX_LABELS] = {0};
582 0 : int num_labels = 0;
583 0 : enum seg6local_action_t seg6l_act = ZEBRA_SEG6_LOCAL_ACTION_UNSPEC;
584 0 : struct seg6local_context seg6l_ctx = {};
585 0 : struct in6_addr seg6_segs = {};
586 0 : int num_segs = 0;
587 0 : struct rtattr *rtnh_tb[RTA_MAX + 1] = {};
588 :
589 0 : int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
590 0 : vrf_id_t nh_vrf_id = vrf_id;
591 :
592 0 : for (;;) {
593 0 : struct nexthop *nh = NULL;
594 :
595 0 : if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
596 : break;
597 :
598 0 : index = rtnh->rtnh_ifindex;
599 0 : if (index) {
600 : /*
601 : * Yes we are looking this up
602 : * for every nexthop and just
603 : * using the last one looked
604 : * up right now
605 : */
606 0 : ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
607 : index);
608 0 : if (ifp)
609 0 : nh_vrf_id = ifp->vrf->vrf_id;
610 : else {
611 0 : flog_warn(
612 : EC_ZEBRA_UNKNOWN_INTERFACE,
613 : "%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
614 : __func__, index);
615 0 : nh_vrf_id = VRF_DEFAULT;
616 : }
617 : } else
618 : nh_vrf_id = vrf_id;
619 :
620 0 : if (rtnh->rtnh_len > sizeof(*rtnh)) {
621 0 : netlink_parse_rtattr(rtnh_tb, RTA_MAX, RTNH_DATA(rtnh),
622 0 : rtnh->rtnh_len - sizeof(*rtnh));
623 0 : if (rtnh_tb[RTA_GATEWAY])
624 0 : gate = RTA_DATA(rtnh_tb[RTA_GATEWAY]);
625 0 : if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
626 0 : && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
627 : == LWTUNNEL_ENCAP_MPLS) {
628 0 : num_labels = parse_encap_mpls(
629 : rtnh_tb[RTA_ENCAP], labels);
630 : }
631 0 : if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
632 0 : && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
633 : == LWTUNNEL_ENCAP_SEG6_LOCAL) {
634 0 : seg6l_act = parse_encap_seg6local(
635 : rtnh_tb[RTA_ENCAP], &seg6l_ctx);
636 : }
637 0 : if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
638 0 : && *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
639 : == LWTUNNEL_ENCAP_SEG6) {
640 0 : num_segs = parse_encap_seg6(rtnh_tb[RTA_ENCAP],
641 : &seg6_segs);
642 : }
643 : }
644 :
645 0 : if (gate && rtm->rtm_family == AF_INET) {
646 0 : if (index)
647 0 : nh = nexthop_from_ipv4_ifindex(
648 : gate, prefsrc, index, nh_vrf_id);
649 : else
650 0 : nh = nexthop_from_ipv4(gate, prefsrc,
651 : nh_vrf_id);
652 0 : } else if (gate && rtm->rtm_family == AF_INET6) {
653 0 : if (index)
654 0 : nh = nexthop_from_ipv6_ifindex(
655 : gate, index, nh_vrf_id);
656 : else
657 0 : nh = nexthop_from_ipv6(gate, nh_vrf_id);
658 : } else
659 0 : nh = nexthop_from_ifindex(index, nh_vrf_id);
660 :
661 0 : if (nh) {
662 0 : nh->weight = rtnh->rtnh_hops + 1;
663 :
664 0 : if (num_labels)
665 0 : nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
666 : num_labels, labels);
667 :
668 0 : if (seg6l_act != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC)
669 0 : nexthop_add_srv6_seg6local(nh, seg6l_act,
670 : &seg6l_ctx);
671 :
672 0 : if (num_segs)
673 0 : nexthop_add_srv6_seg6(nh, &seg6_segs);
674 :
675 0 : if (rtnh->rtnh_flags & RTNH_F_ONLINK)
676 0 : SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK);
677 :
678 : /* Add to temporary list */
679 0 : nexthop_group_add_sorted(ng, nh);
680 : }
681 :
682 0 : if (rtnh->rtnh_len == 0)
683 : break;
684 :
685 0 : len -= NLMSG_ALIGN(rtnh->rtnh_len);
686 0 : rtnh = RTNH_NEXT(rtnh);
687 : }
688 :
689 0 : uint8_t nhop_num = nexthop_group_nexthop_num(ng);
690 :
691 0 : return nhop_num;
692 : }
693 :
694 : /* Looking up routing table by netlink interface. */
695 29 : int netlink_route_change_read_unicast_internal(struct nlmsghdr *h,
696 : ns_id_t ns_id, int startup,
697 : struct zebra_dplane_ctx *ctx)
698 : {
699 29 : int len;
700 29 : struct rtmsg *rtm;
701 29 : struct rtattr *tb[RTA_MAX + 1];
702 29 : uint32_t flags = 0;
703 29 : struct prefix p;
704 29 : struct prefix_ipv6 src_p = {};
705 29 : vrf_id_t vrf_id;
706 29 : bool selfroute;
707 :
708 29 : char anyaddr[16] = {0};
709 :
710 29 : int proto = ZEBRA_ROUTE_KERNEL;
711 29 : int index = 0;
712 29 : int table;
713 29 : int metric = 0;
714 29 : uint32_t mtu = 0;
715 29 : uint8_t distance = 0;
716 29 : route_tag_t tag = 0;
717 29 : uint32_t nhe_id = 0;
718 :
719 29 : void *dest = NULL;
720 29 : void *gate = NULL;
721 29 : void *prefsrc = NULL; /* IPv4 preferred source host address */
722 29 : void *src = NULL; /* IPv6 srcdest source prefix */
723 29 : enum blackhole_type bh_type = BLACKHOLE_UNSPEC;
724 :
725 29 : frrtrace(3, frr_zebra, netlink_route_change_read_unicast, h, ns_id,
726 : startup);
727 :
728 29 : rtm = NLMSG_DATA(h);
729 :
730 29 : if (startup && h->nlmsg_type != RTM_NEWROUTE)
731 : return 0;
732 29 : switch (rtm->rtm_type) {
733 : case RTN_UNICAST:
734 : break;
735 0 : case RTN_BLACKHOLE:
736 0 : bh_type = BLACKHOLE_NULL;
737 0 : break;
738 0 : case RTN_UNREACHABLE:
739 0 : bh_type = BLACKHOLE_REJECT;
740 0 : break;
741 0 : case RTN_PROHIBIT:
742 0 : bh_type = BLACKHOLE_ADMINPROHIB;
743 0 : break;
744 21 : default:
745 21 : if (IS_ZEBRA_DEBUG_KERNEL)
746 0 : zlog_debug("Route rtm_type: %s(%d) intentionally ignoring",
747 : nl_rttype_to_str(rtm->rtm_type),
748 : rtm->rtm_type);
749 : return 0;
750 : }
751 :
752 8 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
753 8 : if (len < 0) {
754 0 : zlog_err(
755 : "%s: Message received from netlink is of a broken size %d %zu",
756 : __func__, h->nlmsg_len,
757 : (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
758 0 : return -1;
759 : }
760 :
761 8 : netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
762 :
763 8 : if (rtm->rtm_flags & RTM_F_CLONED)
764 : return 0;
765 8 : if (rtm->rtm_protocol == RTPROT_REDIRECT)
766 : return 0;
767 8 : if (rtm->rtm_protocol == RTPROT_KERNEL)
768 : return 0;
769 :
770 0 : selfroute = is_selfroute(rtm->rtm_protocol);
771 :
772 0 : if (!startup && selfroute && h->nlmsg_type == RTM_NEWROUTE &&
773 0 : !zrouter.asic_offloaded && !ctx) {
774 0 : if (IS_ZEBRA_DEBUG_KERNEL)
775 0 : zlog_debug("Route type: %d Received that we think we have originated, ignoring",
776 : rtm->rtm_protocol);
777 0 : return 0;
778 : }
779 :
780 : /* We don't care about change notifications for the MPLS table. */
781 : /* TODO: Revisit this. */
782 0 : if (rtm->rtm_family == AF_MPLS)
783 : return 0;
784 :
785 : /* Table corresponding to route. */
786 0 : if (tb[RTA_TABLE])
787 0 : table = *(int *)RTA_DATA(tb[RTA_TABLE]);
788 : else
789 0 : table = rtm->rtm_table;
790 :
791 : /* Map to VRF */
792 0 : vrf_id = vrf_lookup_by_table(table, ns_id);
793 0 : if (vrf_id == VRF_DEFAULT) {
794 0 : if (!is_zebra_valid_kernel_table(table)
795 0 : && !is_zebra_main_routing_table(table))
796 : return 0;
797 : }
798 :
799 0 : if (rtm->rtm_flags & RTM_F_TRAP)
800 0 : flags |= ZEBRA_FLAG_TRAPPED;
801 0 : if (rtm->rtm_flags & RTM_F_OFFLOAD)
802 0 : flags |= ZEBRA_FLAG_OFFLOADED;
803 0 : if (rtm->rtm_flags & RTM_F_OFFLOAD_FAILED)
804 0 : flags |= ZEBRA_FLAG_OFFLOAD_FAILED;
805 :
806 0 : if (h->nlmsg_flags & NLM_F_APPEND)
807 0 : flags |= ZEBRA_FLAG_OUTOFSYNC;
808 :
809 : /* Route which inserted by Zebra. */
810 0 : if (selfroute) {
811 0 : flags |= ZEBRA_FLAG_SELFROUTE;
812 0 : proto = proto2zebra(rtm->rtm_protocol, rtm->rtm_family, false);
813 : }
814 0 : if (tb[RTA_OIF])
815 0 : index = *(int *)RTA_DATA(tb[RTA_OIF]);
816 :
817 0 : if (tb[RTA_DST])
818 0 : dest = RTA_DATA(tb[RTA_DST]);
819 : else
820 : dest = anyaddr;
821 :
822 0 : if (tb[RTA_SRC])
823 0 : src = RTA_DATA(tb[RTA_SRC]);
824 : else
825 : src = anyaddr;
826 :
827 0 : if (tb[RTA_PREFSRC])
828 0 : prefsrc = RTA_DATA(tb[RTA_PREFSRC]);
829 :
830 0 : if (tb[RTA_GATEWAY])
831 0 : gate = RTA_DATA(tb[RTA_GATEWAY]);
832 :
833 0 : if (tb[RTA_NH_ID])
834 0 : nhe_id = *(uint32_t *)RTA_DATA(tb[RTA_NH_ID]);
835 :
836 0 : if (tb[RTA_PRIORITY])
837 0 : metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]);
838 :
839 : #if defined(SUPPORT_REALMS)
840 : if (tb[RTA_FLOW])
841 : tag = *(uint32_t *)RTA_DATA(tb[RTA_FLOW]);
842 : #endif
843 :
844 0 : if (tb[RTA_METRICS]) {
845 0 : struct rtattr *mxrta[RTAX_MAX + 1];
846 :
847 0 : netlink_parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
848 0 : RTA_PAYLOAD(tb[RTA_METRICS]));
849 :
850 0 : if (mxrta[RTAX_MTU])
851 0 : mtu = *(uint32_t *)RTA_DATA(mxrta[RTAX_MTU]);
852 : }
853 :
854 0 : if (rtm->rtm_family == AF_INET) {
855 0 : p.family = AF_INET;
856 0 : if (rtm->rtm_dst_len > IPV4_MAX_BITLEN) {
857 0 : zlog_err(
858 : "Invalid destination prefix length: %u received from kernel route change",
859 : rtm->rtm_dst_len);
860 0 : return -1;
861 : }
862 0 : memcpy(&p.u.prefix4, dest, 4);
863 0 : p.prefixlen = rtm->rtm_dst_len;
864 :
865 0 : if (rtm->rtm_src_len != 0) {
866 0 : flog_warn(
867 : EC_ZEBRA_UNSUPPORTED_V4_SRCDEST,
868 : "unsupported IPv4 sourcedest route (dest %pFX vrf %u)",
869 : &p, vrf_id);
870 0 : return 0;
871 : }
872 :
873 : /* Force debug below to not display anything for source */
874 0 : src_p.prefixlen = 0;
875 0 : } else if (rtm->rtm_family == AF_INET6) {
876 0 : p.family = AF_INET6;
877 0 : if (rtm->rtm_dst_len > IPV6_MAX_BITLEN) {
878 0 : zlog_err(
879 : "Invalid destination prefix length: %u received from kernel route change",
880 : rtm->rtm_dst_len);
881 0 : return -1;
882 : }
883 0 : memcpy(&p.u.prefix6, dest, 16);
884 0 : p.prefixlen = rtm->rtm_dst_len;
885 :
886 0 : src_p.family = AF_INET6;
887 0 : if (rtm->rtm_src_len > IPV6_MAX_BITLEN) {
888 0 : zlog_err(
889 : "Invalid source prefix length: %u received from kernel route change",
890 : rtm->rtm_src_len);
891 0 : return -1;
892 : }
893 0 : memcpy(&src_p.prefix, src, 16);
894 0 : src_p.prefixlen = rtm->rtm_src_len;
895 : } else {
896 : /* We only handle the AFs we handle... */
897 0 : if (IS_ZEBRA_DEBUG_KERNEL)
898 0 : zlog_debug("%s: unknown address-family %u", __func__,
899 : rtm->rtm_family);
900 0 : return 0;
901 : }
902 :
903 : /*
904 : * For ZEBRA_ROUTE_KERNEL types:
905 : *
906 : * The metric/priority of the route received from the kernel
907 : * is a 32 bit number. We are going to interpret the high
908 : * order byte as the Admin Distance and the low order 3 bytes
909 : * as the metric.
910 : *
911 : * This will allow us to do two things:
912 : * 1) Allow the creation of kernel routes that can be
913 : * overridden by zebra.
914 : * 2) Allow the old behavior for 'most' kernel route types
915 : * if a user enters 'ip route ...' v4 routes get a metric
916 : * of 0 and v6 routes get a metric of 1024. Both of these
917 : * values will end up with a admin distance of 0, which
918 : * will cause them to win for the purposes of zebra.
919 : */
920 0 : if (proto == ZEBRA_ROUTE_KERNEL) {
921 0 : distance = (metric >> 24) & 0xFF;
922 0 : metric = (metric & 0x00FFFFFF);
923 : }
924 :
925 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
926 0 : char buf2[PREFIX_STRLEN];
927 :
928 0 : zlog_debug(
929 : "%s %pFX%s%s vrf %s(%u) table_id: %u metric: %d Admin Distance: %d",
930 : nl_msg_type_to_str(h->nlmsg_type), &p,
931 : src_p.prefixlen ? " from " : "",
932 : src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2))
933 : : "",
934 : vrf_id_to_name(vrf_id), vrf_id, table, metric,
935 : distance);
936 : }
937 :
938 0 : afi_t afi = AFI_IP;
939 0 : if (rtm->rtm_family == AF_INET6)
940 0 : afi = AFI_IP6;
941 :
942 0 : if (h->nlmsg_type == RTM_NEWROUTE) {
943 0 : struct route_entry *re;
944 0 : struct nexthop_group *ng = NULL;
945 :
946 0 : re = zebra_rib_route_entry_new(vrf_id, proto, 0, flags, nhe_id,
947 : table, metric, mtu, distance,
948 : tag);
949 0 : if (!nhe_id)
950 0 : ng = nexthop_group_new();
951 :
952 0 : if (!tb[RTA_MULTIPATH]) {
953 0 : struct nexthop *nexthop, nh;
954 :
955 0 : if (!nhe_id) {
956 0 : nh = parse_nexthop_unicast(
957 : ns_id, rtm, tb, bh_type, index, prefsrc,
958 : gate, afi, vrf_id);
959 :
960 0 : nexthop = nexthop_new();
961 0 : *nexthop = nh;
962 0 : nexthop_group_add_sorted(ng, nexthop);
963 : }
964 : } else {
965 : /* This is a multipath route */
966 0 : struct rtnexthop *rtnh =
967 : (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
968 :
969 0 : if (!nhe_id) {
970 0 : uint8_t nhop_num;
971 :
972 : /* Use temporary list of nexthops; parse
973 : * message payload's nexthops.
974 : */
975 0 : nhop_num =
976 0 : parse_multipath_nexthops_unicast(
977 : ns_id, ng, rtm, rtnh, tb,
978 : prefsrc, vrf_id);
979 :
980 0 : zserv_nexthop_num_warn(
981 : __func__, (const struct prefix *)&p,
982 : nhop_num);
983 :
984 0 : if (nhop_num == 0) {
985 0 : nexthop_group_delete(&ng);
986 0 : ng = NULL;
987 : }
988 : }
989 : }
990 0 : if (nhe_id || ng) {
991 0 : dplane_rib_add_multipath(afi, SAFI_UNICAST, &p, &src_p,
992 : re, ng, startup, ctx);
993 0 : if (ng)
994 0 : nexthop_group_delete(&ng);
995 : } else {
996 : /*
997 : * I really don't see how this is possible
998 : * but since we are testing for it let's
999 : * let the end user know why the route
1000 : * that was just received was swallowed
1001 : * up and forgotten
1002 : */
1003 0 : zlog_err(
1004 : "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel",
1005 : __func__, &p);
1006 0 : XFREE(MTYPE_RE, re);
1007 : }
1008 : } else {
1009 0 : if (ctx) {
1010 0 : zlog_err(
1011 : "%s: %pFX RTM_DELROUTE received but received a context as well",
1012 : __func__, &p);
1013 0 : return 0;
1014 : }
1015 :
1016 0 : if (nhe_id) {
1017 0 : rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
1018 : &p, &src_p, NULL, nhe_id, table, metric,
1019 : distance, true);
1020 : } else {
1021 0 : if (!tb[RTA_MULTIPATH]) {
1022 0 : struct nexthop nh;
1023 :
1024 0 : nh = parse_nexthop_unicast(
1025 : ns_id, rtm, tb, bh_type, index, prefsrc,
1026 : gate, afi, vrf_id);
1027 0 : rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
1028 : flags, &p, &src_p, &nh, 0, table,
1029 : metric, distance, true);
1030 : } else {
1031 : /* XXX: need to compare the entire list of
1032 : * nexthops here for NLM_F_APPEND stupidity */
1033 0 : rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
1034 : flags, &p, &src_p, NULL, 0, table,
1035 : metric, distance, true);
1036 : }
1037 : }
1038 : }
1039 :
1040 : return 1;
1041 : }
1042 :
1043 29 : static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
1044 : int startup)
1045 : {
1046 20 : return netlink_route_change_read_unicast_internal(h, ns_id, startup,
1047 : NULL);
1048 : }
1049 :
1050 : static struct mcast_route_data *mroute = NULL;
1051 :
1052 0 : static int netlink_route_change_read_multicast(struct nlmsghdr *h,
1053 : ns_id_t ns_id, int startup)
1054 : {
1055 0 : int len;
1056 0 : struct rtmsg *rtm;
1057 0 : struct rtattr *tb[RTA_MAX + 1];
1058 0 : struct mcast_route_data *m;
1059 0 : int iif = 0;
1060 0 : int count;
1061 0 : int oif[256];
1062 0 : int oif_count = 0;
1063 0 : char oif_list[256] = "\0";
1064 0 : vrf_id_t vrf;
1065 0 : int table;
1066 :
1067 0 : assert(mroute);
1068 0 : m = mroute;
1069 :
1070 0 : rtm = NLMSG_DATA(h);
1071 :
1072 0 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
1073 :
1074 0 : netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len);
1075 :
1076 0 : if (tb[RTA_TABLE])
1077 0 : table = *(int *)RTA_DATA(tb[RTA_TABLE]);
1078 : else
1079 0 : table = rtm->rtm_table;
1080 :
1081 0 : vrf = vrf_lookup_by_table(table, ns_id);
1082 :
1083 0 : if (tb[RTA_IIF])
1084 0 : iif = *(int *)RTA_DATA(tb[RTA_IIF]);
1085 :
1086 0 : if (tb[RTA_SRC]) {
1087 0 : if (rtm->rtm_family == RTNL_FAMILY_IPMR)
1088 0 : m->src.ipaddr_v4 =
1089 : *(struct in_addr *)RTA_DATA(tb[RTA_SRC]);
1090 : else
1091 0 : m->src.ipaddr_v6 =
1092 : *(struct in6_addr *)RTA_DATA(tb[RTA_SRC]);
1093 : }
1094 :
1095 0 : if (tb[RTA_DST]) {
1096 0 : if (rtm->rtm_family == RTNL_FAMILY_IPMR)
1097 0 : m->grp.ipaddr_v4 =
1098 : *(struct in_addr *)RTA_DATA(tb[RTA_DST]);
1099 : else
1100 0 : m->grp.ipaddr_v6 =
1101 : *(struct in6_addr *)RTA_DATA(tb[RTA_DST]);
1102 : }
1103 :
1104 0 : if (tb[RTA_EXPIRES])
1105 0 : m->lastused = *(unsigned long long *)RTA_DATA(tb[RTA_EXPIRES]);
1106 :
1107 0 : if (tb[RTA_MULTIPATH]) {
1108 0 : struct rtnexthop *rtnh =
1109 : (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
1110 :
1111 0 : len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
1112 0 : for (;;) {
1113 0 : if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
1114 : break;
1115 :
1116 0 : oif[oif_count] = rtnh->rtnh_ifindex;
1117 0 : oif_count++;
1118 :
1119 0 : if (rtnh->rtnh_len == 0)
1120 : break;
1121 :
1122 0 : len -= NLMSG_ALIGN(rtnh->rtnh_len);
1123 0 : rtnh = RTNH_NEXT(rtnh);
1124 : }
1125 : }
1126 :
1127 0 : if (rtm->rtm_family == RTNL_FAMILY_IPMR) {
1128 0 : SET_IPADDR_V4(&m->src);
1129 0 : SET_IPADDR_V4(&m->grp);
1130 0 : } else if (rtm->rtm_family == RTNL_FAMILY_IP6MR) {
1131 0 : SET_IPADDR_V6(&m->src);
1132 0 : SET_IPADDR_V6(&m->grp);
1133 : } else {
1134 0 : zlog_warn("%s: Invalid rtm_family received", __func__);
1135 0 : return 0;
1136 : }
1137 :
1138 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
1139 0 : struct interface *ifp = NULL;
1140 0 : struct zebra_vrf *zvrf = NULL;
1141 :
1142 0 : for (count = 0; count < oif_count; count++) {
1143 0 : ifp = if_lookup_by_index(oif[count], vrf);
1144 0 : char temp[256];
1145 :
1146 0 : snprintf(temp, sizeof(temp), "%s(%d) ",
1147 : ifp ? ifp->name : "Unknown", oif[count]);
1148 0 : strlcat(oif_list, temp, sizeof(oif_list));
1149 : }
1150 0 : zvrf = zebra_vrf_lookup_by_id(vrf);
1151 0 : ifp = if_lookup_by_index(iif, vrf);
1152 0 : zlog_debug(
1153 : "MCAST VRF: %s(%d) %s (%pIA,%pIA) IIF: %s(%d) OIF: %s jiffies: %lld",
1154 : zvrf_name(zvrf), vrf, nl_msg_type_to_str(h->nlmsg_type),
1155 : &m->src, &m->grp, ifp ? ifp->name : "Unknown", iif,
1156 : oif_list, m->lastused);
1157 : }
1158 : return 0;
1159 : }
1160 :
1161 11 : int netlink_route_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
1162 : {
1163 11 : int len;
1164 11 : struct rtmsg *rtm;
1165 :
1166 11 : rtm = NLMSG_DATA(h);
1167 :
1168 11 : if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) {
1169 : /* If this is not route add/delete message print warning. */
1170 0 : zlog_debug("Kernel message: %s NS %u",
1171 : nl_msg_type_to_str(h->nlmsg_type), ns_id);
1172 0 : return 0;
1173 : }
1174 :
1175 11 : switch (rtm->rtm_family) {
1176 : case AF_INET:
1177 : case AF_INET6:
1178 11 : break;
1179 :
1180 : case RTNL_FAMILY_IPMR:
1181 : case RTNL_FAMILY_IP6MR:
1182 : /* notifications on IPMR are irrelevant to zebra, we only care
1183 : * about responses to RTM_GETROUTE requests we sent.
1184 : */
1185 : return 0;
1186 :
1187 0 : default:
1188 0 : flog_warn(
1189 : EC_ZEBRA_UNKNOWN_FAMILY,
1190 : "Invalid address family: %u received from kernel route change: %s",
1191 : rtm->rtm_family, nl_msg_type_to_str(h->nlmsg_type));
1192 0 : return 0;
1193 : }
1194 :
1195 : /* Connected route. */
1196 11 : if (IS_ZEBRA_DEBUG_KERNEL)
1197 0 : zlog_debug("%s %s %s proto %s NS %u",
1198 : nl_msg_type_to_str(h->nlmsg_type),
1199 : nl_family_to_str(rtm->rtm_family),
1200 : nl_rttype_to_str(rtm->rtm_type),
1201 : nl_rtproto_to_str(rtm->rtm_protocol), ns_id);
1202 :
1203 :
1204 11 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg));
1205 11 : if (len < 0) {
1206 0 : zlog_err(
1207 : "%s: Message received from netlink is of a broken size: %d %zu",
1208 : __func__, h->nlmsg_len,
1209 : (size_t)NLMSG_LENGTH(sizeof(struct rtmsg)));
1210 0 : return -1;
1211 : }
1212 :
1213 : /* these are "magic" kernel-managed *unicast* routes used for
1214 : * outputting locally generated multicast traffic (which uses unicast
1215 : * handling on Linux because ~reasons~.
1216 : */
1217 11 : if (rtm->rtm_type == RTN_MULTICAST)
1218 : return 0;
1219 :
1220 9 : netlink_route_change_read_unicast(h, ns_id, startup);
1221 9 : return 0;
1222 : }
1223 :
1224 : /* Request for specific route information from the kernel */
1225 2 : static int netlink_request_route(struct zebra_ns *zns, int family, int type)
1226 : {
1227 2 : struct {
1228 : struct nlmsghdr n;
1229 : struct rtmsg rtm;
1230 : } req;
1231 :
1232 : /* Form the request, specifying filter (rtattr) if needed. */
1233 2 : memset(&req, 0, sizeof(req));
1234 2 : req.n.nlmsg_type = type;
1235 2 : req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
1236 2 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
1237 2 : req.rtm.rtm_family = family;
1238 :
1239 2 : return netlink_request(&zns->netlink_cmd, &req);
1240 : }
1241 :
1242 : /* Routing table read function using netlink interface. Only called
1243 : bootstrap time. */
1244 1 : int netlink_route_read(struct zebra_ns *zns)
1245 : {
1246 1 : int ret;
1247 1 : struct zebra_dplane_info dp_info;
1248 :
1249 1 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
1250 :
1251 : /* Get IPv4 routing table. */
1252 1 : ret = netlink_request_route(zns, AF_INET, RTM_GETROUTE);
1253 1 : if (ret < 0)
1254 : return ret;
1255 1 : ret = netlink_parse_info(netlink_route_change_read_unicast,
1256 : &zns->netlink_cmd, &dp_info, 0, true);
1257 1 : if (ret < 0)
1258 : return ret;
1259 :
1260 : /* Get IPv6 routing table. */
1261 1 : ret = netlink_request_route(zns, AF_INET6, RTM_GETROUTE);
1262 1 : if (ret < 0)
1263 : return ret;
1264 1 : ret = netlink_parse_info(netlink_route_change_read_unicast,
1265 : &zns->netlink_cmd, &dp_info, 0, true);
1266 1 : if (ret < 0)
1267 : return ret;
1268 :
1269 : return 0;
1270 : }
1271 :
1272 : /*
1273 : * The function returns true if the gateway info could be added
1274 : * to the message, otherwise false is returned.
1275 : */
1276 0 : static bool _netlink_route_add_gateway_info(uint8_t route_family,
1277 : uint8_t gw_family,
1278 : struct nlmsghdr *nlmsg,
1279 : size_t req_size, int bytelen,
1280 : const struct nexthop *nexthop)
1281 : {
1282 0 : if (route_family == AF_MPLS) {
1283 0 : struct gw_family_t gw_fam;
1284 :
1285 0 : gw_fam.family = gw_family;
1286 0 : if (gw_family == AF_INET)
1287 0 : memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
1288 : else
1289 0 : memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
1290 0 : if (!nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family,
1291 0 : bytelen + 2))
1292 0 : return false;
1293 : } else {
1294 0 : if (!(nexthop->rparent
1295 0 : && IS_MAPPED_IPV6(&nexthop->rparent->gate.ipv6))) {
1296 0 : if (gw_family == AF_INET) {
1297 0 : if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
1298 0 : &nexthop->gate.ipv4, bytelen))
1299 : return false;
1300 : } else {
1301 0 : if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY,
1302 0 : &nexthop->gate.ipv6, bytelen))
1303 : return false;
1304 : }
1305 : }
1306 : }
1307 :
1308 : return true;
1309 : }
1310 :
1311 11 : static int build_label_stack(struct mpls_label_stack *nh_label,
1312 : mpls_lse_t *out_lse, char *label_buf,
1313 : size_t label_buf_size)
1314 : {
1315 11 : char label_buf1[20];
1316 11 : int num_labels = 0;
1317 :
1318 11 : for (int i = 0; nh_label && i < nh_label->num_labels; i++) {
1319 0 : if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL)
1320 0 : continue;
1321 :
1322 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
1323 0 : if (!num_labels)
1324 0 : snprintf(label_buf, label_buf_size, "label %u",
1325 : nh_label->label[i]);
1326 : else {
1327 0 : snprintf(label_buf1, sizeof(label_buf1), "/%u",
1328 : nh_label->label[i]);
1329 0 : strlcat(label_buf, label_buf1, label_buf_size);
1330 : }
1331 : }
1332 :
1333 0 : out_lse[num_labels] =
1334 0 : mpls_lse_encode(nh_label->label[i], 0, 0, 0);
1335 0 : num_labels++;
1336 : }
1337 :
1338 11 : return num_labels;
1339 : }
1340 :
1341 0 : static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label,
1342 : struct nlmsghdr *nlmsg,
1343 : size_t buflen, struct rtmsg *rtmsg,
1344 : char *label_buf,
1345 : size_t label_buf_size)
1346 : {
1347 0 : mpls_lse_t out_lse[MPLS_MAX_LABELS];
1348 0 : int num_labels;
1349 :
1350 : /*
1351 : * label_buf is *only* currently used within debugging.
1352 : * As such when we assign it we are guarding it inside
1353 : * a debug test. If you want to change this make sure
1354 : * you fix this assumption
1355 : */
1356 0 : label_buf[0] = '\0';
1357 :
1358 0 : num_labels =
1359 0 : build_label_stack(nh_label, out_lse, label_buf, label_buf_size);
1360 :
1361 0 : if (num_labels) {
1362 : /* Set the BoS bit */
1363 0 : out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT);
1364 :
1365 0 : if (rtmsg->rtm_family == AF_MPLS) {
1366 0 : if (!nl_attr_put(nlmsg, buflen, RTA_NEWDST, &out_lse,
1367 : num_labels * sizeof(mpls_lse_t)))
1368 : return false;
1369 : } else {
1370 0 : struct rtattr *nest;
1371 :
1372 0 : if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE,
1373 : LWTUNNEL_ENCAP_MPLS))
1374 : return false;
1375 :
1376 0 : nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP);
1377 0 : if (!nest)
1378 : return false;
1379 :
1380 0 : if (!nl_attr_put(nlmsg, buflen, MPLS_IPTUNNEL_DST,
1381 : &out_lse,
1382 : num_labels * sizeof(mpls_lse_t)))
1383 : return false;
1384 0 : nl_attr_nest_end(nlmsg, nest);
1385 : }
1386 : }
1387 :
1388 : return true;
1389 : }
1390 :
1391 0 : static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop,
1392 : int family,
1393 : struct nlmsghdr *nlmsg,
1394 : size_t buflen, int bytelen)
1395 : {
1396 0 : if (family == AF_INET) {
1397 0 : if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
1398 0 : if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
1399 0 : &nexthop->rmap_src.ipv4, bytelen))
1400 : return false;
1401 0 : } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
1402 0 : if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
1403 0 : &nexthop->src.ipv4, bytelen))
1404 : return false;
1405 : }
1406 0 : } else if (family == AF_INET6) {
1407 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
1408 0 : if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
1409 0 : &nexthop->rmap_src.ipv6, bytelen))
1410 : return false;
1411 0 : } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) {
1412 0 : if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC,
1413 0 : &nexthop->src.ipv6, bytelen))
1414 : return false;
1415 : }
1416 : }
1417 :
1418 : return true;
1419 : }
1420 :
1421 0 : static ssize_t fill_seg6ipt_encap(char *buffer, size_t buflen,
1422 : const struct in6_addr *seg)
1423 : {
1424 0 : struct seg6_iptunnel_encap *ipt;
1425 0 : struct ipv6_sr_hdr *srh;
1426 0 : const size_t srhlen = 24;
1427 :
1428 : /*
1429 : * Caution: Support only SINGLE-SID, not MULTI-SID
1430 : * This function only supports the case where segs represents
1431 : * a single SID. If you want to extend the SRv6 functionality,
1432 : * you should improve the Boundary Check.
1433 : * Ex. In case of set a SID-List include multiple-SIDs as an
1434 : * argument of the Transit Behavior, we must support variable
1435 : * boundary check for buflen.
1436 : */
1437 0 : if (buflen < (sizeof(struct seg6_iptunnel_encap) +
1438 : sizeof(struct ipv6_sr_hdr) + 16))
1439 : return -1;
1440 :
1441 0 : memset(buffer, 0, buflen);
1442 :
1443 0 : ipt = (struct seg6_iptunnel_encap *)buffer;
1444 0 : ipt->mode = SEG6_IPTUN_MODE_ENCAP;
1445 0 : srh = ipt->srh;
1446 0 : srh->hdrlen = (srhlen >> 3) - 1;
1447 0 : srh->type = 4;
1448 0 : srh->segments_left = 0;
1449 0 : srh->first_segment = 0;
1450 0 : memcpy(&srh->segments[0], seg, sizeof(struct in6_addr));
1451 :
1452 0 : return srhlen + 4;
1453 : }
1454 :
1455 : /* This function takes a nexthop as argument and adds
1456 : * the appropriate netlink attributes to an existing
1457 : * netlink message.
1458 : *
1459 : * @param routedesc: Human readable description of route type
1460 : * (direct/recursive, single-/multipath)
1461 : * @param bytelen: Length of addresses in bytes.
1462 : * @param nexthop: Nexthop information
1463 : * @param nlmsg: nlmsghdr structure to fill in.
1464 : * @param req_size: The size allocated for the message.
1465 : *
1466 : * The function returns true if the nexthop could be added
1467 : * to the message, otherwise false is returned.
1468 : */
1469 0 : static bool _netlink_route_build_singlepath(const struct prefix *p,
1470 : const char *routedesc, int bytelen,
1471 : const struct nexthop *nexthop,
1472 : struct nlmsghdr *nlmsg,
1473 : struct rtmsg *rtmsg,
1474 : size_t req_size, int cmd)
1475 : {
1476 :
1477 0 : char label_buf[256];
1478 0 : struct vrf *vrf;
1479 0 : char addrstr[INET6_ADDRSTRLEN];
1480 :
1481 0 : assert(nexthop);
1482 :
1483 0 : vrf = vrf_lookup_by_id(nexthop->vrf_id);
1484 :
1485 0 : if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
1486 : req_size, rtmsg, label_buf,
1487 : sizeof(label_buf)))
1488 : return false;
1489 :
1490 0 : if (nexthop->nh_srv6) {
1491 0 : if (nexthop->nh_srv6->seg6local_action !=
1492 : ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
1493 0 : struct rtattr *nest;
1494 0 : const struct seg6local_context *ctx;
1495 :
1496 0 : ctx = &nexthop->nh_srv6->seg6local_ctx;
1497 0 : if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
1498 : LWTUNNEL_ENCAP_SEG6_LOCAL))
1499 : return false;
1500 :
1501 0 : nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
1502 0 : if (!nest)
1503 : return false;
1504 :
1505 0 : switch (nexthop->nh_srv6->seg6local_action) {
1506 0 : case ZEBRA_SEG6_LOCAL_ACTION_END:
1507 0 : if (!nl_attr_put32(nlmsg, req_size,
1508 : SEG6_LOCAL_ACTION,
1509 : SEG6_LOCAL_ACTION_END))
1510 : return false;
1511 : break;
1512 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_X:
1513 0 : if (!nl_attr_put32(nlmsg, req_size,
1514 : SEG6_LOCAL_ACTION,
1515 : SEG6_LOCAL_ACTION_END_X))
1516 : return false;
1517 0 : if (!nl_attr_put(nlmsg, req_size,
1518 0 : SEG6_LOCAL_NH6, &ctx->nh6,
1519 : sizeof(struct in6_addr)))
1520 : return false;
1521 : break;
1522 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_T:
1523 0 : if (!nl_attr_put32(nlmsg, req_size,
1524 : SEG6_LOCAL_ACTION,
1525 : SEG6_LOCAL_ACTION_END_T))
1526 : return false;
1527 0 : if (!nl_attr_put32(nlmsg, req_size,
1528 : SEG6_LOCAL_TABLE,
1529 0 : ctx->table))
1530 : return false;
1531 : break;
1532 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
1533 0 : if (!nl_attr_put32(nlmsg, req_size,
1534 : SEG6_LOCAL_ACTION,
1535 : SEG6_LOCAL_ACTION_END_DX4))
1536 : return false;
1537 0 : if (!nl_attr_put(nlmsg, req_size,
1538 0 : SEG6_LOCAL_NH4, &ctx->nh4,
1539 : sizeof(struct in_addr)))
1540 : return false;
1541 : break;
1542 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
1543 0 : if (!nl_attr_put32(nlmsg, req_size,
1544 : SEG6_LOCAL_ACTION,
1545 : SEG6_LOCAL_ACTION_END_DT6))
1546 : return false;
1547 0 : if (!nl_attr_put32(nlmsg, req_size,
1548 : SEG6_LOCAL_TABLE,
1549 0 : ctx->table))
1550 : return false;
1551 : break;
1552 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
1553 0 : if (!nl_attr_put32(nlmsg, req_size,
1554 : SEG6_LOCAL_ACTION,
1555 : SEG6_LOCAL_ACTION_END_DT4))
1556 : return false;
1557 0 : if (!nl_attr_put32(nlmsg, req_size,
1558 : SEG6_LOCAL_VRFTABLE,
1559 0 : ctx->table))
1560 : return false;
1561 : break;
1562 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
1563 0 : if (!nl_attr_put32(nlmsg, req_size,
1564 : SEG6_LOCAL_ACTION,
1565 : SEG6_LOCAL_ACTION_END_DT46))
1566 : return false;
1567 0 : if (!nl_attr_put32(nlmsg, req_size,
1568 : SEG6_LOCAL_VRFTABLE,
1569 0 : ctx->table))
1570 : return false;
1571 : break;
1572 0 : case ZEBRA_SEG6_LOCAL_ACTION_END_DX2:
1573 : case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
1574 : case ZEBRA_SEG6_LOCAL_ACTION_END_B6:
1575 : case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP:
1576 : case ZEBRA_SEG6_LOCAL_ACTION_END_BM:
1577 : case ZEBRA_SEG6_LOCAL_ACTION_END_S:
1578 : case ZEBRA_SEG6_LOCAL_ACTION_END_AS:
1579 : case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
1580 : case ZEBRA_SEG6_LOCAL_ACTION_END_BPF:
1581 : case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
1582 0 : zlog_err("%s: unsupport seg6local behaviour action=%u",
1583 : __func__,
1584 : nexthop->nh_srv6->seg6local_action);
1585 0 : return false;
1586 : }
1587 0 : nl_attr_nest_end(nlmsg, nest);
1588 : }
1589 :
1590 0 : if (!sid_zero(&nexthop->nh_srv6->seg6_segs)) {
1591 0 : char tun_buf[4096];
1592 0 : ssize_t tun_len;
1593 0 : struct rtattr *nest;
1594 :
1595 0 : if (!nl_attr_put16(nlmsg, req_size, RTA_ENCAP_TYPE,
1596 : LWTUNNEL_ENCAP_SEG6))
1597 0 : return false;
1598 0 : nest = nl_attr_nest(nlmsg, req_size, RTA_ENCAP);
1599 0 : if (!nest)
1600 : return false;
1601 0 : tun_len = fill_seg6ipt_encap(tun_buf, sizeof(tun_buf),
1602 0 : &nexthop->nh_srv6->seg6_segs);
1603 0 : if (tun_len < 0)
1604 : return false;
1605 0 : if (!nl_attr_put(nlmsg, req_size, SEG6_IPTUNNEL_SRH,
1606 : tun_buf, tun_len))
1607 : return false;
1608 0 : nl_attr_nest_end(nlmsg, nest);
1609 : }
1610 : }
1611 :
1612 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
1613 0 : rtmsg->rtm_flags |= RTNH_F_ONLINK;
1614 :
1615 0 : if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
1616 0 : rtmsg->rtm_flags |= RTNH_F_ONLINK;
1617 0 : if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
1618 : return false;
1619 0 : if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
1620 : return false;
1621 :
1622 0 : if (cmd == RTM_NEWROUTE) {
1623 0 : if (!_netlink_route_encode_nexthop_src(
1624 : nexthop, AF_INET, nlmsg, req_size, bytelen))
1625 : return false;
1626 : }
1627 :
1628 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1629 0 : zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
1630 : __func__, routedesc, p, ipv4_ll_buf,
1631 : label_buf, nexthop->ifindex,
1632 : VRF_LOGNAME(vrf), nexthop->vrf_id);
1633 0 : return true;
1634 : }
1635 :
1636 0 : if (nexthop->type == NEXTHOP_TYPE_IPV4
1637 0 : || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
1638 : /* Send deletes to the kernel without specifying the next-hop */
1639 0 : if (cmd != RTM_DELROUTE) {
1640 0 : if (!_netlink_route_add_gateway_info(
1641 : rtmsg->rtm_family, AF_INET, nlmsg, req_size,
1642 : bytelen, nexthop))
1643 : return false;
1644 : }
1645 :
1646 0 : if (cmd == RTM_NEWROUTE) {
1647 0 : if (!_netlink_route_encode_nexthop_src(
1648 : nexthop, AF_INET, nlmsg, req_size, bytelen))
1649 : return false;
1650 : }
1651 :
1652 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
1653 0 : inet_ntop(AF_INET, &nexthop->gate.ipv4, addrstr,
1654 : sizeof(addrstr));
1655 0 : zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
1656 : __func__, routedesc, p, addrstr, label_buf,
1657 : nexthop->ifindex, VRF_LOGNAME(vrf),
1658 : nexthop->vrf_id);
1659 : }
1660 : }
1661 :
1662 0 : if (nexthop->type == NEXTHOP_TYPE_IPV6
1663 0 : || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
1664 0 : if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
1665 : AF_INET6, nlmsg, req_size,
1666 : bytelen, nexthop))
1667 : return false;
1668 :
1669 0 : if (cmd == RTM_NEWROUTE) {
1670 0 : if (!_netlink_route_encode_nexthop_src(
1671 : nexthop, AF_INET6, nlmsg, req_size,
1672 : bytelen))
1673 : return false;
1674 : }
1675 :
1676 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
1677 0 : inet_ntop(AF_INET6, &nexthop->gate.ipv6, addrstr,
1678 : sizeof(addrstr));
1679 0 : zlog_debug("%s: (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
1680 : __func__, routedesc, p, addrstr, label_buf,
1681 : nexthop->ifindex, VRF_LOGNAME(vrf),
1682 : nexthop->vrf_id);
1683 : }
1684 : }
1685 :
1686 : /*
1687 : * We have the ifindex so we should always send it
1688 : * This is especially useful if we are doing route
1689 : * leaking.
1690 : */
1691 0 : if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
1692 0 : if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex))
1693 : return false;
1694 : }
1695 :
1696 0 : if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
1697 0 : if (cmd == RTM_NEWROUTE) {
1698 0 : if (!_netlink_route_encode_nexthop_src(
1699 : nexthop, AF_INET, nlmsg, req_size, bytelen))
1700 : return false;
1701 : }
1702 :
1703 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1704 0 : zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
1705 : __func__, routedesc, p, nexthop->ifindex,
1706 : VRF_LOGNAME(vrf), nexthop->vrf_id);
1707 : }
1708 :
1709 : return true;
1710 : }
1711 :
1712 : /* This function appends tag value as rtnl flow attribute
1713 : * to the given netlink msg only if value is less than 256.
1714 : * Used only if SUPPORT_REALMS enabled.
1715 : *
1716 : * @param nlmsg: nlmsghdr structure to fill in.
1717 : * @param maxlen: The size allocated for the message.
1718 : * @param tag: The route tag.
1719 : *
1720 : * The function returns true if the flow attribute could
1721 : * be added to the message, otherwise false is returned.
1722 : */
1723 0 : static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen,
1724 : route_tag_t tag)
1725 : {
1726 0 : if (tag > 0 && tag <= 255) {
1727 0 : if (!nl_attr_put32(n, maxlen, RTA_FLOW, tag))
1728 : return false;
1729 : }
1730 : return true;
1731 : }
1732 :
1733 : /* This function takes a nexthop as argument and
1734 : * appends to the given netlink msg. If the nexthop
1735 : * defines a preferred source, the src parameter
1736 : * will be modified to point to that src, otherwise
1737 : * it will be kept unmodified.
1738 : *
1739 : * @param routedesc: Human readable description of route type
1740 : * (direct/recursive, single-/multipath)
1741 : * @param bytelen: Length of addresses in bytes.
1742 : * @param nexthop: Nexthop information
1743 : * @param nlmsg: nlmsghdr structure to fill in.
1744 : * @param req_size: The size allocated for the message.
1745 : * @param src: pointer pointing to a location where
1746 : * the prefsrc should be stored.
1747 : *
1748 : * The function returns true if the nexthop could be added
1749 : * to the message, otherwise false is returned.
1750 : */
1751 0 : static bool _netlink_route_build_multipath(
1752 : const struct prefix *p, const char *routedesc, int bytelen,
1753 : const struct nexthop *nexthop, struct nlmsghdr *nlmsg, size_t req_size,
1754 : struct rtmsg *rtmsg, const union g_addr **src, route_tag_t tag)
1755 : {
1756 0 : char label_buf[256];
1757 0 : struct vrf *vrf;
1758 0 : struct rtnexthop *rtnh;
1759 :
1760 0 : rtnh = nl_attr_rtnh(nlmsg, req_size);
1761 0 : if (rtnh == NULL)
1762 : return false;
1763 :
1764 0 : assert(nexthop);
1765 :
1766 0 : vrf = vrf_lookup_by_id(nexthop->vrf_id);
1767 :
1768 0 : if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg,
1769 : req_size, rtmsg, label_buf,
1770 : sizeof(label_buf)))
1771 : return false;
1772 :
1773 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
1774 0 : rtnh->rtnh_flags |= RTNH_F_ONLINK;
1775 :
1776 0 : if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) {
1777 0 : rtnh->rtnh_flags |= RTNH_F_ONLINK;
1778 0 : if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4))
1779 : return false;
1780 0 : rtnh->rtnh_ifindex = nexthop->ifindex;
1781 0 : if (nexthop->weight)
1782 0 : rtnh->rtnh_hops = nexthop->weight - 1;
1783 :
1784 0 : if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
1785 0 : *src = &nexthop->rmap_src;
1786 0 : else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
1787 0 : *src = &nexthop->src;
1788 :
1789 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1790 0 : zlog_debug(
1791 : "%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)",
1792 : __func__, routedesc, p, ipv4_ll_buf, label_buf,
1793 : nexthop->ifindex, VRF_LOGNAME(vrf),
1794 : nexthop->vrf_id);
1795 0 : nl_attr_rtnh_end(nlmsg, rtnh);
1796 0 : return true;
1797 : }
1798 :
1799 0 : if (nexthop->type == NEXTHOP_TYPE_IPV4
1800 0 : || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
1801 0 : if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET,
1802 : nlmsg, req_size, bytelen,
1803 : nexthop))
1804 : return false;
1805 :
1806 0 : if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
1807 0 : *src = &nexthop->rmap_src;
1808 0 : else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
1809 0 : *src = &nexthop->src;
1810 :
1811 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1812 0 : zlog_debug("%s: (%s): %pFX nexthop via %pI4 %s if %u vrf %s(%u)",
1813 : __func__, routedesc, p, &nexthop->gate.ipv4,
1814 : label_buf, nexthop->ifindex,
1815 : VRF_LOGNAME(vrf), nexthop->vrf_id);
1816 : }
1817 0 : if (nexthop->type == NEXTHOP_TYPE_IPV6
1818 0 : || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
1819 0 : if (!_netlink_route_add_gateway_info(rtmsg->rtm_family,
1820 : AF_INET6, nlmsg, req_size,
1821 : bytelen, nexthop))
1822 : return false;
1823 :
1824 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
1825 0 : *src = &nexthop->rmap_src;
1826 0 : else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
1827 0 : *src = &nexthop->src;
1828 :
1829 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1830 0 : zlog_debug("%s: (%s): %pFX nexthop via %pI6 %s if %u vrf %s(%u)",
1831 : __func__, routedesc, p, &nexthop->gate.ipv6,
1832 : label_buf, nexthop->ifindex,
1833 : VRF_LOGNAME(vrf), nexthop->vrf_id);
1834 : }
1835 :
1836 : /*
1837 : * We have figured out the ifindex so we should always send it
1838 : * This is especially useful if we are doing route
1839 : * leaking.
1840 : */
1841 0 : if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
1842 0 : rtnh->rtnh_ifindex = nexthop->ifindex;
1843 :
1844 : /* ifindex */
1845 0 : if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
1846 0 : if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY)
1847 0 : *src = &nexthop->rmap_src;
1848 0 : else if (nexthop->src.ipv4.s_addr != INADDR_ANY)
1849 0 : *src = &nexthop->src;
1850 :
1851 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1852 0 : zlog_debug("%s: (%s): %pFX nexthop via if %u vrf %s(%u)",
1853 : __func__, routedesc, p, nexthop->ifindex,
1854 : VRF_LOGNAME(vrf), nexthop->vrf_id);
1855 : }
1856 :
1857 0 : if (nexthop->weight)
1858 0 : rtnh->rtnh_hops = nexthop->weight - 1;
1859 :
1860 0 : if (!_netlink_set_tag(nlmsg, req_size, tag))
1861 : return false;
1862 :
1863 0 : nl_attr_rtnh_end(nlmsg, rtnh);
1864 0 : return true;
1865 : }
1866 :
1867 : static inline bool
1868 0 : _netlink_mpls_build_singlepath(const struct prefix *p, const char *routedesc,
1869 : const struct zebra_nhlfe *nhlfe,
1870 : struct nlmsghdr *nlmsg, struct rtmsg *rtmsg,
1871 : size_t req_size, int cmd)
1872 : {
1873 0 : int bytelen;
1874 0 : uint8_t family;
1875 :
1876 0 : family = NHLFE_FAMILY(nhlfe);
1877 0 : bytelen = (family == AF_INET ? 4 : 16);
1878 0 : return _netlink_route_build_singlepath(p, routedesc, bytelen,
1879 : nhlfe->nexthop, nlmsg, rtmsg,
1880 : req_size, cmd);
1881 : }
1882 :
1883 :
1884 : static inline bool
1885 0 : _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc,
1886 : const struct zebra_nhlfe *nhlfe,
1887 : struct nlmsghdr *nlmsg, size_t req_size,
1888 : struct rtmsg *rtmsg, const union g_addr **src)
1889 : {
1890 0 : int bytelen;
1891 0 : uint8_t family;
1892 :
1893 0 : family = NHLFE_FAMILY(nhlfe);
1894 0 : bytelen = (family == AF_INET ? 4 : 16);
1895 0 : return _netlink_route_build_multipath(p, routedesc, bytelen,
1896 : nhlfe->nexthop, nlmsg, req_size,
1897 : rtmsg, src, 0);
1898 : }
1899 :
1900 0 : static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc)
1901 : {
1902 0 : if (IS_ZEBRA_DEBUG_KERNEL)
1903 0 : zlog_debug("netlink_mpls_multipath_msg_encode() (%s): %s %u/20",
1904 : routedesc, nl_msg_type_to_str(cmd), label);
1905 0 : }
1906 :
1907 0 : static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla,
1908 : int llalen, ns_id_t ns_id, uint8_t family,
1909 : bool permanent, uint8_t protocol)
1910 : {
1911 0 : struct {
1912 : struct nlmsghdr n;
1913 : struct ndmsg ndm;
1914 : char buf[256];
1915 : } req;
1916 :
1917 0 : struct zebra_ns *zns = zebra_ns_lookup(ns_id);
1918 :
1919 0 : memset(&req, 0, sizeof(req));
1920 :
1921 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
1922 0 : req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1923 0 : req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH
1924 0 : req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
1925 :
1926 0 : req.ndm.ndm_family = family;
1927 0 : req.ndm.ndm_ifindex = ifindex;
1928 0 : req.ndm.ndm_type = RTN_UNICAST;
1929 0 : if (cmd == RTM_NEWNEIGH) {
1930 0 : if (!permanent)
1931 0 : req.ndm.ndm_state = NUD_REACHABLE;
1932 : else
1933 0 : req.ndm.ndm_state = NUD_PERMANENT;
1934 : } else
1935 0 : req.ndm.ndm_state = NUD_FAILED;
1936 :
1937 0 : nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol,
1938 : sizeof(protocol));
1939 0 : req.ndm.ndm_type = RTN_UNICAST;
1940 0 : nl_attr_put(&req.n, sizeof(req), NDA_DST, addr,
1941 0 : family2addrsize(family));
1942 0 : if (lla)
1943 0 : nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
1944 :
1945 0 : return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
1946 : false);
1947 : }
1948 :
1949 0 : static bool nexthop_set_src(const struct nexthop *nexthop, int family,
1950 : union g_addr *src)
1951 : {
1952 0 : if (family == AF_INET) {
1953 0 : if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) {
1954 0 : src->ipv4 = nexthop->rmap_src.ipv4;
1955 0 : return true;
1956 0 : } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) {
1957 0 : src->ipv4 = nexthop->src.ipv4;
1958 0 : return true;
1959 : }
1960 0 : } else if (family == AF_INET6) {
1961 0 : if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) {
1962 0 : src->ipv6 = nexthop->rmap_src.ipv6;
1963 0 : return true;
1964 0 : } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) {
1965 0 : src->ipv6 = nexthop->src.ipv6;
1966 0 : return true;
1967 : }
1968 : }
1969 :
1970 : return false;
1971 : }
1972 :
1973 : /*
1974 : * The function returns true if the attribute could be added
1975 : * to the message, otherwise false is returned.
1976 : */
1977 0 : static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
1978 : struct nexthop *nh)
1979 : {
1980 0 : struct rtattr *nest;
1981 :
1982 0 : switch (nh->nh_encap_type) {
1983 0 : case NET_VXLAN:
1984 0 : if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type))
1985 : return false;
1986 :
1987 0 : nest = nl_attr_nest(n, nlen, RTA_ENCAP);
1988 0 : if (!nest)
1989 : return false;
1990 :
1991 0 : if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */,
1992 : nh->nh_encap.vni))
1993 : return false;
1994 0 : nl_attr_nest_end(n, nest);
1995 0 : break;
1996 : }
1997 :
1998 : return true;
1999 : }
2000 :
2001 : /*
2002 : * Routing table change via netlink interface, using a dataplane context object
2003 : *
2004 : * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
2005 : * otherwise the number of bytes written to buf.
2006 : */
2007 0 : ssize_t netlink_route_multipath_msg_encode(int cmd,
2008 : struct zebra_dplane_ctx *ctx,
2009 : uint8_t *data, size_t datalen,
2010 : bool fpm, bool force_nhg)
2011 : {
2012 0 : int bytelen;
2013 0 : struct nexthop *nexthop = NULL;
2014 0 : unsigned int nexthop_num;
2015 0 : const char *routedesc;
2016 0 : bool setsrc = false;
2017 0 : union g_addr src;
2018 0 : const struct prefix *p, *src_p;
2019 0 : uint32_t table_id;
2020 0 : struct nlsock *nl;
2021 0 : route_tag_t tag = 0;
2022 :
2023 0 : struct {
2024 : struct nlmsghdr n;
2025 : struct rtmsg r;
2026 : char buf[];
2027 0 : } *req = (void *)data;
2028 :
2029 0 : p = dplane_ctx_get_dest(ctx);
2030 0 : src_p = dplane_ctx_get_src(ctx);
2031 :
2032 0 : if (datalen < sizeof(*req))
2033 : return 0;
2034 :
2035 0 : nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
2036 :
2037 0 : memset(req, 0, sizeof(*req));
2038 :
2039 0 : bytelen = (p->family == AF_INET ? 4 : 16);
2040 :
2041 0 : req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
2042 0 : req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
2043 :
2044 0 : if ((cmd == RTM_NEWROUTE) &&
2045 0 : ((p->family == AF_INET) || v6_rr_semantics))
2046 0 : req->n.nlmsg_flags |= NLM_F_REPLACE;
2047 :
2048 0 : req->n.nlmsg_type = cmd;
2049 :
2050 0 : req->n.nlmsg_pid = nl->snl.nl_pid;
2051 :
2052 0 : req->r.rtm_family = p->family;
2053 0 : req->r.rtm_dst_len = p->prefixlen;
2054 0 : req->r.rtm_src_len = src_p ? src_p->prefixlen : 0;
2055 0 : req->r.rtm_scope = RT_SCOPE_UNIVERSE;
2056 :
2057 0 : if (cmd == RTM_DELROUTE)
2058 0 : req->r.rtm_protocol = zebra2proto(dplane_ctx_get_old_type(ctx));
2059 : else
2060 0 : req->r.rtm_protocol = zebra2proto(dplane_ctx_get_type(ctx));
2061 :
2062 : /*
2063 : * blackhole routes are not RTN_UNICAST, they are
2064 : * RTN_ BLACKHOLE|UNREACHABLE|PROHIBIT
2065 : * so setting this value as a RTN_UNICAST would
2066 : * cause the route lookup of just the prefix
2067 : * to fail. So no need to specify this for
2068 : * the RTM_DELROUTE case
2069 : */
2070 0 : if (cmd != RTM_DELROUTE)
2071 0 : req->r.rtm_type = RTN_UNICAST;
2072 :
2073 0 : if (!nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen))
2074 : return 0;
2075 0 : if (src_p) {
2076 0 : if (!nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix,
2077 : bytelen))
2078 : return 0;
2079 : }
2080 :
2081 : /* Metric. */
2082 : /* Hardcode the metric for all routes coming from zebra. Metric isn't
2083 : * used
2084 : * either by the kernel or by zebra. Its purely for calculating best
2085 : * path(s)
2086 : * by the routing protocol and for communicating with protocol peers.
2087 : */
2088 0 : if (!nl_attr_put32(&req->n, datalen, RTA_PRIORITY,
2089 : ROUTE_INSTALLATION_METRIC))
2090 : return 0;
2091 :
2092 : #if defined(SUPPORT_REALMS)
2093 : if (cmd == RTM_DELROUTE)
2094 : tag = dplane_ctx_get_old_tag(ctx);
2095 : else
2096 : tag = dplane_ctx_get_tag(ctx);
2097 : #endif
2098 :
2099 : /* Table corresponding to this route. */
2100 0 : table_id = dplane_ctx_get_table(ctx);
2101 0 : if (table_id < 256)
2102 0 : req->r.rtm_table = table_id;
2103 : else {
2104 0 : req->r.rtm_table = RT_TABLE_UNSPEC;
2105 0 : if (!nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id))
2106 : return 0;
2107 : }
2108 :
2109 0 : if (IS_ZEBRA_DEBUG_KERNEL)
2110 0 : zlog_debug(
2111 : "%s: %s %pFX vrf %u(%u)", __func__,
2112 : nl_msg_type_to_str(cmd), p, dplane_ctx_get_vrf(ctx),
2113 : table_id);
2114 :
2115 : /*
2116 : * If we are not updating the route and we have received
2117 : * a route delete, then all we need to fill in is the
2118 : * prefix information to tell the kernel to schwack
2119 : * it.
2120 : */
2121 0 : if (cmd == RTM_DELROUTE) {
2122 0 : if (!_netlink_set_tag(&req->n, datalen, tag))
2123 : return 0;
2124 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
2125 : }
2126 :
2127 0 : if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) {
2128 0 : struct rtattr *nest;
2129 0 : uint32_t mtu = dplane_ctx_get_mtu(ctx);
2130 0 : uint32_t nexthop_mtu = dplane_ctx_get_nh_mtu(ctx);
2131 :
2132 0 : if (!mtu || (nexthop_mtu && nexthop_mtu < mtu))
2133 0 : mtu = nexthop_mtu;
2134 :
2135 0 : nest = nl_attr_nest(&req->n, datalen, RTA_METRICS);
2136 0 : if (nest == NULL)
2137 0 : return 0;
2138 :
2139 0 : if (!nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu)))
2140 : return 0;
2141 0 : nl_attr_nest_end(&req->n, nest);
2142 : }
2143 :
2144 : /*
2145 : * Always install blackhole routes without using nexthops, because of
2146 : * the following kernel problems:
2147 : * 1. Kernel nexthops don't suport unreachable/prohibit route types.
2148 : * 2. Blackhole kernel nexthops are deleted when loopback is down.
2149 : */
2150 0 : nexthop = dplane_ctx_get_ng(ctx)->nexthop;
2151 0 : if (nexthop) {
2152 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
2153 0 : nexthop = nexthop->resolved;
2154 :
2155 0 : if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
2156 0 : switch (nexthop->bh_type) {
2157 0 : case BLACKHOLE_ADMINPROHIB:
2158 0 : req->r.rtm_type = RTN_PROHIBIT;
2159 0 : break;
2160 0 : case BLACKHOLE_REJECT:
2161 0 : req->r.rtm_type = RTN_UNREACHABLE;
2162 0 : break;
2163 0 : case BLACKHOLE_UNSPEC:
2164 : case BLACKHOLE_NULL:
2165 0 : req->r.rtm_type = RTN_BLACKHOLE;
2166 0 : break;
2167 : }
2168 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
2169 : }
2170 : }
2171 :
2172 0 : if ((!fpm && kernel_nexthops_supported()
2173 0 : && (!proto_nexthops_only()
2174 0 : || is_proto_nhg(dplane_ctx_get_nhe_id(ctx), 0)))
2175 0 : || (fpm && force_nhg)) {
2176 : /* Kernel supports nexthop objects */
2177 0 : if (IS_ZEBRA_DEBUG_KERNEL)
2178 0 : zlog_debug("%s: %pFX nhg_id is %u", __func__, p,
2179 : dplane_ctx_get_nhe_id(ctx));
2180 :
2181 0 : if (!nl_attr_put32(&req->n, datalen, RTA_NH_ID,
2182 : dplane_ctx_get_nhe_id(ctx)))
2183 : return 0;
2184 :
2185 : /* Have to determine src still */
2186 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
2187 0 : if (setsrc)
2188 : break;
2189 :
2190 0 : setsrc = nexthop_set_src(nexthop, p->family, &src);
2191 : }
2192 :
2193 0 : if (setsrc) {
2194 0 : if (p->family == AF_INET) {
2195 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2196 : &src.ipv4, bytelen))
2197 : return 0;
2198 0 : } else if (p->family == AF_INET6) {
2199 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2200 : &src.ipv6, bytelen))
2201 : return 0;
2202 : }
2203 : }
2204 :
2205 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
2206 : }
2207 :
2208 : /* Count overall nexthops so we can decide whether to use singlepath
2209 : * or multipath case.
2210 : */
2211 0 : nexthop_num = 0;
2212 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
2213 0 : if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
2214 0 : continue;
2215 0 : if (!NEXTHOP_IS_ACTIVE(nexthop->flags))
2216 0 : continue;
2217 :
2218 0 : nexthop_num++;
2219 : }
2220 :
2221 : /* Singlepath case. */
2222 0 : if (nexthop_num == 1) {
2223 0 : nexthop_num = 0;
2224 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
2225 0 : if (CHECK_FLAG(nexthop->flags,
2226 : NEXTHOP_FLAG_RECURSIVE)) {
2227 :
2228 0 : if (setsrc)
2229 0 : continue;
2230 :
2231 0 : setsrc = nexthop_set_src(nexthop, p->family,
2232 : &src);
2233 0 : continue;
2234 : }
2235 :
2236 0 : if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
2237 0 : routedesc = nexthop->rparent
2238 : ? "recursive, single-path"
2239 0 : : "single-path";
2240 :
2241 0 : if (!_netlink_set_tag(&req->n, datalen, tag))
2242 : return 0;
2243 :
2244 0 : if (!_netlink_route_build_singlepath(
2245 : p, routedesc, bytelen, nexthop,
2246 : &req->n, &req->r, datalen, cmd))
2247 : return 0;
2248 : nexthop_num++;
2249 : break;
2250 : }
2251 :
2252 : /*
2253 : * Add encapsulation information when installing via
2254 : * FPM.
2255 : */
2256 0 : if (fpm) {
2257 0 : if (!netlink_route_nexthop_encap(
2258 : &req->n, datalen, nexthop))
2259 : return 0;
2260 : }
2261 : }
2262 :
2263 0 : if (setsrc) {
2264 0 : if (p->family == AF_INET) {
2265 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2266 : &src.ipv4, bytelen))
2267 : return 0;
2268 0 : } else if (p->family == AF_INET6) {
2269 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2270 : &src.ipv6, bytelen))
2271 : return 0;
2272 : }
2273 : }
2274 : } else { /* Multipath case */
2275 0 : struct rtattr *nest;
2276 0 : const union g_addr *src1 = NULL;
2277 :
2278 0 : nest = nl_attr_nest(&req->n, datalen, RTA_MULTIPATH);
2279 0 : if (nest == NULL)
2280 0 : return 0;
2281 :
2282 0 : nexthop_num = 0;
2283 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) {
2284 0 : if (CHECK_FLAG(nexthop->flags,
2285 : NEXTHOP_FLAG_RECURSIVE)) {
2286 : /* This only works for IPv4 now */
2287 0 : if (setsrc)
2288 0 : continue;
2289 :
2290 0 : setsrc = nexthop_set_src(nexthop, p->family,
2291 : &src);
2292 0 : continue;
2293 : }
2294 :
2295 0 : if (NEXTHOP_IS_ACTIVE(nexthop->flags)) {
2296 0 : routedesc = nexthop->rparent
2297 : ? "recursive, multipath"
2298 0 : : "multipath";
2299 0 : nexthop_num++;
2300 :
2301 0 : if (!_netlink_route_build_multipath(
2302 : p, routedesc, bytelen, nexthop,
2303 : &req->n, datalen, &req->r, &src1,
2304 : tag))
2305 : return 0;
2306 :
2307 0 : if (!setsrc && src1) {
2308 0 : if (p->family == AF_INET)
2309 0 : src.ipv4 = src1->ipv4;
2310 0 : else if (p->family == AF_INET6)
2311 0 : src.ipv6 = src1->ipv6;
2312 :
2313 : setsrc = 1;
2314 : }
2315 : }
2316 : }
2317 :
2318 0 : nl_attr_nest_end(&req->n, nest);
2319 :
2320 : /*
2321 : * Add encapsulation information when installing via
2322 : * FPM.
2323 : */
2324 0 : if (fpm) {
2325 0 : for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx),
2326 : nexthop)) {
2327 0 : if (CHECK_FLAG(nexthop->flags,
2328 : NEXTHOP_FLAG_RECURSIVE))
2329 0 : continue;
2330 0 : if (!netlink_route_nexthop_encap(
2331 : &req->n, datalen, nexthop))
2332 : return 0;
2333 : }
2334 : }
2335 :
2336 :
2337 0 : if (setsrc) {
2338 0 : if (p->family == AF_INET) {
2339 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2340 : &src.ipv4, bytelen))
2341 : return 0;
2342 0 : } else if (p->family == AF_INET6) {
2343 0 : if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC,
2344 : &src.ipv6, bytelen))
2345 : return 0;
2346 : }
2347 0 : if (IS_ZEBRA_DEBUG_KERNEL)
2348 0 : zlog_debug("Setting source");
2349 : }
2350 : }
2351 :
2352 : /* If there is no useful nexthop then return. */
2353 0 : if (nexthop_num == 0) {
2354 0 : if (IS_ZEBRA_DEBUG_KERNEL)
2355 0 : zlog_debug("%s: No useful nexthop.", __func__);
2356 : }
2357 :
2358 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
2359 : }
2360 :
2361 0 : int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
2362 : {
2363 0 : uint32_t actual_table;
2364 0 : int suc = 0;
2365 0 : struct mcast_route_data *mr = (struct mcast_route_data *)in;
2366 0 : struct {
2367 : struct nlmsghdr n;
2368 : struct rtmsg rtm;
2369 : char buf[256];
2370 : } req;
2371 :
2372 0 : mroute = mr;
2373 0 : struct zebra_ns *zns;
2374 :
2375 0 : zns = zvrf->zns;
2376 0 : memset(&req, 0, sizeof(req));
2377 :
2378 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
2379 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
2380 0 : req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid;
2381 :
2382 0 : req.n.nlmsg_type = RTM_GETROUTE;
2383 :
2384 0 : if (mroute->family == AF_INET) {
2385 0 : req.rtm.rtm_family = RTNL_FAMILY_IPMR;
2386 0 : req.rtm.rtm_dst_len = IPV4_MAX_BITLEN;
2387 0 : req.rtm.rtm_src_len = IPV4_MAX_BITLEN;
2388 :
2389 0 : nl_attr_put(&req.n, sizeof(req), RTA_SRC,
2390 0 : &mroute->src.ipaddr_v4,
2391 : sizeof(mroute->src.ipaddr_v4));
2392 0 : nl_attr_put(&req.n, sizeof(req), RTA_DST,
2393 0 : &mroute->grp.ipaddr_v4,
2394 : sizeof(mroute->grp.ipaddr_v4));
2395 : } else {
2396 0 : req.rtm.rtm_family = RTNL_FAMILY_IP6MR;
2397 0 : req.rtm.rtm_dst_len = IPV6_MAX_BITLEN;
2398 0 : req.rtm.rtm_src_len = IPV6_MAX_BITLEN;
2399 :
2400 0 : nl_attr_put(&req.n, sizeof(req), RTA_SRC,
2401 0 : &mroute->src.ipaddr_v6,
2402 : sizeof(mroute->src.ipaddr_v6));
2403 0 : nl_attr_put(&req.n, sizeof(req), RTA_DST,
2404 0 : &mroute->grp.ipaddr_v6,
2405 : sizeof(mroute->grp.ipaddr_v6));
2406 : }
2407 :
2408 : /*
2409 : * What?
2410 : *
2411 : * So during the namespace cleanup we started storing
2412 : * the zvrf table_id for the default table as RT_TABLE_MAIN
2413 : * which is what the normal routing table for ip routing is.
2414 : * This change caused this to break our lookups of sg data
2415 : * because prior to this change the zvrf->table_id was 0
2416 : * and when the pim multicast kernel code saw a 0,
2417 : * it was auto-translated to RT_TABLE_DEFAULT. But since
2418 : * we are now passing in RT_TABLE_MAIN there is no auto-translation
2419 : * and the kernel goes screw you and the delicious cookies you
2420 : * are trying to give me. So now we have this little hack.
2421 : */
2422 0 : if (mroute->family == AF_INET)
2423 0 : actual_table = (zvrf->table_id == RT_TABLE_MAIN)
2424 : ? RT_TABLE_DEFAULT
2425 0 : : zvrf->table_id;
2426 : else
2427 0 : actual_table = zvrf->table_id;
2428 :
2429 0 : nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table);
2430 :
2431 0 : suc = netlink_talk(netlink_route_change_read_multicast, &req.n,
2432 : &zns->netlink_cmd, zns, false);
2433 :
2434 0 : mroute = NULL;
2435 0 : return suc;
2436 : }
2437 :
2438 : /* Char length to debug ID with */
2439 : #define ID_LENGTH 10
2440 :
2441 0 : static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
2442 : uint32_t id,
2443 : const struct nh_grp *z_grp,
2444 : const uint8_t count, bool resilient,
2445 : const struct nhg_resilience *nhgr)
2446 0 : {
2447 0 : struct nexthop_grp grp[count];
2448 : /* Need space for max group size, "/", and null term */
2449 0 : char buf[(MULTIPATH_NUM * (ID_LENGTH + 1)) + 1];
2450 0 : char buf1[ID_LENGTH + 2];
2451 :
2452 0 : buf[0] = '\0';
2453 :
2454 0 : memset(grp, 0, sizeof(grp));
2455 :
2456 0 : if (count) {
2457 0 : for (int i = 0; i < count; i++) {
2458 0 : grp[i].id = z_grp[i].id;
2459 0 : grp[i].weight = z_grp[i].weight - 1;
2460 :
2461 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
2462 0 : if (i == 0)
2463 0 : snprintf(buf, sizeof(buf1), "group %u",
2464 : grp[i].id);
2465 : else {
2466 0 : snprintf(buf1, sizeof(buf1), "/%u",
2467 : grp[i].id);
2468 0 : strlcat(buf, buf1, sizeof(buf));
2469 : }
2470 : }
2471 : }
2472 0 : if (!nl_attr_put(n, req_size, NHA_GROUP, grp,
2473 : count * sizeof(*grp)))
2474 : return false;
2475 :
2476 0 : if (resilient) {
2477 0 : struct rtattr *nest;
2478 :
2479 0 : nest = nl_attr_nest(n, req_size, NHA_RES_GROUP);
2480 :
2481 0 : nl_attr_put16(n, req_size, NHA_RES_GROUP_BUCKETS,
2482 0 : nhgr->buckets);
2483 0 : nl_attr_put32(n, req_size, NHA_RES_GROUP_IDLE_TIMER,
2484 0 : nhgr->idle_timer * 1000);
2485 0 : nl_attr_put32(n, req_size,
2486 : NHA_RES_GROUP_UNBALANCED_TIMER,
2487 0 : nhgr->unbalanced_timer * 1000);
2488 0 : nl_attr_nest_end(n, nest);
2489 :
2490 0 : nl_attr_put16(n, req_size, NHA_GROUP_TYPE,
2491 : NEXTHOP_GRP_TYPE_RES);
2492 : }
2493 : }
2494 :
2495 0 : if (IS_ZEBRA_DEBUG_KERNEL)
2496 0 : zlog_debug("%s: ID (%u): %s", __func__, id, buf);
2497 :
2498 : return true;
2499 : }
2500 :
2501 : /**
2502 : * Next hop packet encoding helper function.
2503 : *
2504 : * \param[in] cmd netlink command.
2505 : * \param[in] ctx dataplane context (information snapshot).
2506 : * \param[out] buf buffer to hold the packet.
2507 : * \param[in] buflen amount of buffer bytes.
2508 : *
2509 : * \returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer
2510 : * otherwise the number of bytes written to buf.
2511 : */
2512 18 : ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
2513 : const struct zebra_dplane_ctx *ctx,
2514 : void *buf, size_t buflen, bool fpm)
2515 : {
2516 18 : struct {
2517 : struct nlmsghdr n;
2518 : struct nhmsg nhm;
2519 : char buf[];
2520 18 : } *req = buf;
2521 :
2522 18 : mpls_lse_t out_lse[MPLS_MAX_LABELS];
2523 18 : char label_buf[256];
2524 18 : int num_labels = 0;
2525 18 : uint32_t id = dplane_ctx_get_nhe_id(ctx);
2526 18 : int type = dplane_ctx_get_nhe_type(ctx);
2527 18 : struct rtattr *nest;
2528 18 : uint16_t encap;
2529 18 : struct nlsock *nl =
2530 18 : kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
2531 :
2532 18 : if (!id) {
2533 0 : flog_err(
2534 : EC_ZEBRA_NHG_FIB_UPDATE,
2535 : "Failed trying to update a nexthop group in the kernel that does not have an ID");
2536 0 : return -1;
2537 : }
2538 :
2539 : /*
2540 : * Nothing to do if the kernel doesn't support nexthop objects or
2541 : * we dont want to install this type of NHG, but FPM may possible to
2542 : * handle this.
2543 : */
2544 18 : if (!fpm && !kernel_nexthops_supported()) {
2545 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
2546 0 : zlog_debug(
2547 : "%s: nhg_id %u (%s): kernel nexthops not supported, ignoring",
2548 : __func__, id, zebra_route_string(type));
2549 0 : return 0;
2550 : }
2551 :
2552 18 : if (proto_nexthops_only() && !is_proto_nhg(id, type)) {
2553 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
2554 0 : zlog_debug(
2555 : "%s: nhg_id %u (%s): proto-based nexthops only, ignoring",
2556 : __func__, id, zebra_route_string(type));
2557 0 : return 0;
2558 : }
2559 :
2560 18 : label_buf[0] = '\0';
2561 :
2562 18 : if (buflen < sizeof(*req))
2563 : return 0;
2564 :
2565 18 : memset(req, 0, sizeof(*req));
2566 :
2567 18 : req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
2568 18 : req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
2569 :
2570 18 : if (cmd == RTM_NEWNEXTHOP)
2571 11 : req->n.nlmsg_flags |= NLM_F_REPLACE;
2572 :
2573 18 : req->n.nlmsg_type = cmd;
2574 18 : req->n.nlmsg_pid = nl->snl.nl_pid;
2575 :
2576 18 : req->nhm.nh_family = AF_UNSPEC;
2577 : /* TODO: Scope? */
2578 :
2579 18 : if (!nl_attr_put32(&req->n, buflen, NHA_ID, id))
2580 : return 0;
2581 :
2582 18 : if (cmd == RTM_NEWNEXTHOP) {
2583 : /*
2584 : * We distinguish between a "group", which is a collection
2585 : * of ids, and a singleton nexthop with an id. The
2586 : * group is installed as an id that just refers to a list of
2587 : * other ids.
2588 : */
2589 11 : if (dplane_ctx_get_nhe_nh_grp_count(ctx)) {
2590 0 : const struct nexthop_group *nhg;
2591 0 : const struct nhg_resilience *nhgr;
2592 :
2593 0 : nhg = dplane_ctx_get_nhe_ng(ctx);
2594 0 : nhgr = &nhg->nhgr;
2595 0 : if (!_netlink_nexthop_build_group(
2596 : &req->n, buflen, id,
2597 : dplane_ctx_get_nhe_nh_grp(ctx),
2598 0 : dplane_ctx_get_nhe_nh_grp_count(ctx),
2599 0 : !!nhgr->buckets, nhgr))
2600 : return 0;
2601 : } else {
2602 22 : const struct nexthop *nh =
2603 11 : dplane_ctx_get_nhe_ng(ctx)->nexthop;
2604 11 : afi_t afi = dplane_ctx_get_nhe_afi(ctx);
2605 :
2606 11 : if (afi == AFI_IP)
2607 7 : req->nhm.nh_family = AF_INET;
2608 4 : else if (afi == AFI_IP6)
2609 4 : req->nhm.nh_family = AF_INET6;
2610 :
2611 11 : switch (nh->type) {
2612 0 : case NEXTHOP_TYPE_IPV4:
2613 : case NEXTHOP_TYPE_IPV4_IFINDEX:
2614 0 : if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
2615 0 : &nh->gate.ipv4,
2616 : IPV4_MAX_BYTELEN))
2617 : return 0;
2618 : break;
2619 0 : case NEXTHOP_TYPE_IPV6:
2620 : case NEXTHOP_TYPE_IPV6_IFINDEX:
2621 0 : if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY,
2622 0 : &nh->gate.ipv6,
2623 : IPV6_MAX_BYTELEN))
2624 : return 0;
2625 : break;
2626 0 : case NEXTHOP_TYPE_BLACKHOLE:
2627 0 : if (!nl_attr_put(&req->n, buflen, NHA_BLACKHOLE,
2628 : NULL, 0))
2629 : return 0;
2630 : /* Blackhole shouldn't have anymore attributes
2631 : */
2632 0 : goto nexthop_done;
2633 : case NEXTHOP_TYPE_IFINDEX:
2634 : /* Don't need anymore info for this */
2635 : break;
2636 : }
2637 :
2638 11 : if (!nh->ifindex) {
2639 0 : flog_err(
2640 : EC_ZEBRA_NHG_FIB_UPDATE,
2641 : "Context received for kernel nexthop update without an interface");
2642 0 : return -1;
2643 : }
2644 :
2645 11 : if (!nl_attr_put32(&req->n, buflen, NHA_OIF,
2646 : nh->ifindex))
2647 : return 0;
2648 :
2649 11 : if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
2650 0 : req->nhm.nh_flags |= RTNH_F_ONLINK;
2651 :
2652 11 : num_labels =
2653 11 : build_label_stack(nh->nh_label, out_lse,
2654 : label_buf, sizeof(label_buf));
2655 :
2656 11 : if (num_labels) {
2657 : /* Set the BoS bit */
2658 0 : out_lse[num_labels - 1] |=
2659 0 : htonl(1 << MPLS_LS_S_SHIFT);
2660 :
2661 : /*
2662 : * TODO: MPLS unsupported for now in kernel.
2663 : */
2664 0 : if (req->nhm.nh_family == AF_MPLS)
2665 0 : goto nexthop_done;
2666 :
2667 0 : encap = LWTUNNEL_ENCAP_MPLS;
2668 0 : if (!nl_attr_put16(&req->n, buflen,
2669 : NHA_ENCAP_TYPE, encap))
2670 : return 0;
2671 0 : nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP);
2672 0 : if (!nest)
2673 : return 0;
2674 0 : if (!nl_attr_put(
2675 : &req->n, buflen, MPLS_IPTUNNEL_DST,
2676 : &out_lse,
2677 : num_labels * sizeof(mpls_lse_t)))
2678 : return 0;
2679 :
2680 0 : nl_attr_nest_end(&req->n, nest);
2681 : }
2682 :
2683 11 : if (nh->nh_srv6) {
2684 0 : if (nh->nh_srv6->seg6local_action !=
2685 : ZEBRA_SEG6_LOCAL_ACTION_UNSPEC) {
2686 0 : uint32_t action;
2687 0 : uint16_t encap;
2688 0 : struct rtattr *nest;
2689 0 : const struct seg6local_context *ctx;
2690 :
2691 0 : req->nhm.nh_family = AF_INET6;
2692 0 : action = nh->nh_srv6->seg6local_action;
2693 0 : ctx = &nh->nh_srv6->seg6local_ctx;
2694 0 : encap = LWTUNNEL_ENCAP_SEG6_LOCAL;
2695 0 : if (!nl_attr_put(&req->n, buflen,
2696 : NHA_ENCAP_TYPE,
2697 : &encap,
2698 : sizeof(uint16_t)))
2699 0 : return 0;
2700 :
2701 0 : nest = nl_attr_nest(&req->n, buflen,
2702 : NHA_ENCAP | NLA_F_NESTED);
2703 0 : if (!nest)
2704 : return 0;
2705 :
2706 0 : switch (action) {
2707 0 : case SEG6_LOCAL_ACTION_END:
2708 0 : if (!nl_attr_put32(
2709 : &req->n, buflen,
2710 : SEG6_LOCAL_ACTION,
2711 : SEG6_LOCAL_ACTION_END))
2712 : return 0;
2713 : break;
2714 0 : case SEG6_LOCAL_ACTION_END_X:
2715 0 : if (!nl_attr_put32(
2716 : &req->n, buflen,
2717 : SEG6_LOCAL_ACTION,
2718 : SEG6_LOCAL_ACTION_END_X))
2719 : return 0;
2720 0 : if (!nl_attr_put(
2721 : &req->n, buflen,
2722 0 : SEG6_LOCAL_NH6, &ctx->nh6,
2723 : sizeof(struct in6_addr)))
2724 : return 0;
2725 : break;
2726 0 : case SEG6_LOCAL_ACTION_END_T:
2727 0 : if (!nl_attr_put32(
2728 : &req->n, buflen,
2729 : SEG6_LOCAL_ACTION,
2730 : SEG6_LOCAL_ACTION_END_T))
2731 : return 0;
2732 0 : if (!nl_attr_put32(
2733 : &req->n, buflen,
2734 : SEG6_LOCAL_TABLE,
2735 0 : ctx->table))
2736 : return 0;
2737 : break;
2738 0 : case SEG6_LOCAL_ACTION_END_DX4:
2739 0 : if (!nl_attr_put32(
2740 : &req->n, buflen,
2741 : SEG6_LOCAL_ACTION,
2742 : SEG6_LOCAL_ACTION_END_DX4))
2743 : return 0;
2744 0 : if (!nl_attr_put(
2745 : &req->n, buflen,
2746 0 : SEG6_LOCAL_NH4, &ctx->nh4,
2747 : sizeof(struct in_addr)))
2748 : return 0;
2749 : break;
2750 0 : case SEG6_LOCAL_ACTION_END_DT6:
2751 0 : if (!nl_attr_put32(
2752 : &req->n, buflen,
2753 : SEG6_LOCAL_ACTION,
2754 : SEG6_LOCAL_ACTION_END_DT6))
2755 : return 0;
2756 0 : if (!nl_attr_put32(
2757 : &req->n, buflen,
2758 : SEG6_LOCAL_TABLE,
2759 0 : ctx->table))
2760 : return 0;
2761 : break;
2762 0 : case SEG6_LOCAL_ACTION_END_DT4:
2763 0 : if (!nl_attr_put32(
2764 : &req->n, buflen,
2765 : SEG6_LOCAL_ACTION,
2766 : SEG6_LOCAL_ACTION_END_DT4))
2767 : return 0;
2768 0 : if (!nl_attr_put32(
2769 : &req->n, buflen,
2770 : SEG6_LOCAL_VRFTABLE,
2771 0 : ctx->table))
2772 : return 0;
2773 : break;
2774 0 : case SEG6_LOCAL_ACTION_END_DT46:
2775 0 : if (!nl_attr_put32(
2776 : &req->n, buflen,
2777 : SEG6_LOCAL_ACTION,
2778 : SEG6_LOCAL_ACTION_END_DT46))
2779 : return 0;
2780 0 : if (!nl_attr_put32(
2781 : &req->n, buflen,
2782 : SEG6_LOCAL_VRFTABLE,
2783 0 : ctx->table))
2784 : return 0;
2785 : break;
2786 0 : default:
2787 0 : zlog_err("%s: unsupport seg6local behaviour action=%u",
2788 : __func__, action);
2789 0 : return 0;
2790 : }
2791 0 : nl_attr_nest_end(&req->n, nest);
2792 : }
2793 :
2794 0 : if (!sid_zero(&nh->nh_srv6->seg6_segs)) {
2795 0 : char tun_buf[4096];
2796 0 : ssize_t tun_len;
2797 0 : struct rtattr *nest;
2798 :
2799 0 : if (!nl_attr_put16(&req->n, buflen,
2800 : NHA_ENCAP_TYPE,
2801 : LWTUNNEL_ENCAP_SEG6))
2802 0 : return 0;
2803 0 : nest = nl_attr_nest(&req->n, buflen,
2804 : NHA_ENCAP | NLA_F_NESTED);
2805 0 : if (!nest)
2806 : return 0;
2807 0 : tun_len = fill_seg6ipt_encap(tun_buf,
2808 : sizeof(tun_buf),
2809 0 : &nh->nh_srv6->seg6_segs);
2810 0 : if (tun_len < 0)
2811 : return 0;
2812 0 : if (!nl_attr_put(&req->n, buflen,
2813 : SEG6_IPTUNNEL_SRH,
2814 : tun_buf, tun_len))
2815 : return 0;
2816 0 : nl_attr_nest_end(&req->n, nest);
2817 : }
2818 : }
2819 :
2820 11 : nexthop_done:
2821 :
2822 11 : if (IS_ZEBRA_DEBUG_KERNEL)
2823 0 : zlog_debug("%s: ID (%u): %pNHv(%d) vrf %s(%u) %s ",
2824 : __func__, id, nh, nh->ifindex,
2825 : vrf_id_to_name(nh->vrf_id),
2826 : nh->vrf_id, label_buf);
2827 : }
2828 :
2829 11 : req->nhm.nh_protocol = zebra2proto(type);
2830 :
2831 7 : } else if (cmd != RTM_DELNEXTHOP) {
2832 0 : flog_err(
2833 : EC_ZEBRA_NHG_FIB_UPDATE,
2834 : "Nexthop group kernel update command (%d) does not exist",
2835 : cmd);
2836 0 : return -1;
2837 : }
2838 :
2839 18 : if (IS_ZEBRA_DEBUG_KERNEL)
2840 0 : zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd),
2841 : id);
2842 :
2843 18 : return NLMSG_ALIGN(req->n.nlmsg_len);
2844 : }
2845 :
2846 18 : static ssize_t netlink_nexthop_msg_encoder(struct zebra_dplane_ctx *ctx,
2847 : void *buf, size_t buflen)
2848 : {
2849 18 : enum dplane_op_e op;
2850 18 : int cmd = 0;
2851 :
2852 18 : op = dplane_ctx_get_op(ctx);
2853 18 : if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
2854 : cmd = RTM_NEWNEXTHOP;
2855 7 : else if (op == DPLANE_OP_NH_DELETE)
2856 : cmd = RTM_DELNEXTHOP;
2857 : else {
2858 0 : flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
2859 : "Context received for kernel nexthop update with incorrect OP code (%u)",
2860 : op);
2861 0 : return -1;
2862 : }
2863 :
2864 18 : return netlink_nexthop_msg_encode(cmd, ctx, buf, buflen, false);
2865 : }
2866 :
2867 : enum netlink_msg_status
2868 18 : netlink_put_nexthop_update_msg(struct nl_batch *bth,
2869 : struct zebra_dplane_ctx *ctx)
2870 : {
2871 : /* Nothing to do if the kernel doesn't support nexthop objects */
2872 18 : if (!kernel_nexthops_supported())
2873 : return FRR_NETLINK_SUCCESS;
2874 :
2875 18 : return netlink_batch_add_msg(bth, ctx, netlink_nexthop_msg_encoder,
2876 : false);
2877 : }
2878 :
2879 0 : static ssize_t netlink_newroute_msg_encoder(struct zebra_dplane_ctx *ctx,
2880 : void *buf, size_t buflen)
2881 : {
2882 0 : return netlink_route_multipath_msg_encode(RTM_NEWROUTE, ctx, buf,
2883 : buflen, false, false);
2884 : }
2885 :
2886 0 : static ssize_t netlink_delroute_msg_encoder(struct zebra_dplane_ctx *ctx,
2887 : void *buf, size_t buflen)
2888 : {
2889 0 : return netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, buf,
2890 : buflen, false, false);
2891 : }
2892 :
2893 : enum netlink_msg_status
2894 24 : netlink_put_route_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
2895 : {
2896 24 : int cmd;
2897 24 : const struct prefix *p = dplane_ctx_get_dest(ctx);
2898 :
2899 24 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) {
2900 : cmd = RTM_DELROUTE;
2901 13 : } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) {
2902 : cmd = RTM_NEWROUTE;
2903 0 : } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) {
2904 :
2905 0 : if (p->family == AF_INET || v6_rr_semantics) {
2906 : /* Single 'replace' operation */
2907 :
2908 : /*
2909 : * With route replace semantics in place
2910 : * for v4 routes and the new route is a system
2911 : * route we do not install anything.
2912 : * The problem here is that the new system
2913 : * route should cause us to withdraw from
2914 : * the kernel the old non-system route
2915 : */
2916 0 : if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))
2917 0 : && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
2918 0 : return netlink_batch_add_msg(
2919 : bth, ctx, netlink_delroute_msg_encoder,
2920 : true);
2921 : } else {
2922 : /*
2923 : * So v6 route replace semantics are not in
2924 : * the kernel at this point as I understand it.
2925 : * so let's do a delete then an add.
2926 : * In the future once v6 route replace semantics
2927 : * are in we can figure out what to do here to
2928 : * allow working with old and new kernels.
2929 : *
2930 : * I'm also intentionally ignoring the failure case
2931 : * of the route delete. If that happens yeah we're
2932 : * screwed.
2933 : */
2934 0 : if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx)))
2935 0 : netlink_batch_add_msg(
2936 : bth, ctx, netlink_delroute_msg_encoder,
2937 : true);
2938 : }
2939 :
2940 : cmd = RTM_NEWROUTE;
2941 : } else
2942 : return FRR_NETLINK_ERROR;
2943 :
2944 24 : if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)))
2945 24 : return FRR_NETLINK_SUCCESS;
2946 :
2947 0 : return netlink_batch_add_msg(bth, ctx,
2948 : cmd == RTM_NEWROUTE
2949 : ? netlink_newroute_msg_encoder
2950 : : netlink_delroute_msg_encoder,
2951 : false);
2952 : }
2953 :
2954 : /**
2955 : * netlink_nexthop_process_nh() - Parse the gatway/if info from a new nexthop
2956 : *
2957 : * @tb: Netlink RTA data
2958 : * @family: Address family in the nhmsg
2959 : * @ifp: Interface connected - this should be NULL, we fill it in
2960 : * @ns_id: Namspace id
2961 : *
2962 : * Return: New nexthop
2963 : */
2964 0 : static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
2965 : unsigned char family,
2966 : struct interface **ifp,
2967 : ns_id_t ns_id)
2968 : {
2969 0 : struct nexthop nh = {};
2970 0 : void *gate = NULL;
2971 0 : enum nexthop_types_t type = 0;
2972 0 : int if_index = 0;
2973 0 : size_t sz = 0;
2974 0 : struct interface *ifp_lookup;
2975 :
2976 0 : if_index = *(int *)RTA_DATA(tb[NHA_OIF]);
2977 :
2978 :
2979 0 : if (tb[NHA_GATEWAY]) {
2980 0 : switch (family) {
2981 : case AF_INET:
2982 : type = NEXTHOP_TYPE_IPV4_IFINDEX;
2983 : sz = 4;
2984 : break;
2985 0 : case AF_INET6:
2986 0 : type = NEXTHOP_TYPE_IPV6_IFINDEX;
2987 0 : sz = 16;
2988 0 : break;
2989 0 : default:
2990 0 : flog_warn(
2991 : EC_ZEBRA_BAD_NHG_MESSAGE,
2992 : "Nexthop gateway with bad address family (%d) received from kernel",
2993 : family);
2994 0 : return nh;
2995 : }
2996 0 : gate = RTA_DATA(tb[NHA_GATEWAY]);
2997 : } else
2998 : type = NEXTHOP_TYPE_IFINDEX;
2999 :
3000 0 : if (type)
3001 0 : nh.type = type;
3002 :
3003 0 : if (gate)
3004 0 : memcpy(&(nh.gate), gate, sz);
3005 :
3006 0 : if (if_index)
3007 0 : nh.ifindex = if_index;
3008 :
3009 0 : ifp_lookup =
3010 0 : if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), nh.ifindex);
3011 :
3012 0 : if (ifp)
3013 0 : *ifp = ifp_lookup;
3014 0 : if (ifp_lookup)
3015 0 : nh.vrf_id = ifp_lookup->vrf->vrf_id;
3016 : else {
3017 0 : flog_warn(
3018 : EC_ZEBRA_UNKNOWN_INTERFACE,
3019 : "%s: Unknown nexthop interface %u received, defaulting to VRF_DEFAULT",
3020 : __func__, nh.ifindex);
3021 :
3022 0 : nh.vrf_id = VRF_DEFAULT;
3023 : }
3024 :
3025 0 : if (tb[NHA_ENCAP] && tb[NHA_ENCAP_TYPE]) {
3026 0 : uint16_t encap_type = *(uint16_t *)RTA_DATA(tb[NHA_ENCAP_TYPE]);
3027 0 : int num_labels = 0;
3028 :
3029 0 : mpls_label_t labels[MPLS_MAX_LABELS] = {0};
3030 :
3031 0 : if (encap_type == LWTUNNEL_ENCAP_MPLS)
3032 0 : num_labels = parse_encap_mpls(tb[NHA_ENCAP], labels);
3033 :
3034 0 : if (num_labels)
3035 0 : nexthop_add_labels(&nh, ZEBRA_LSP_STATIC, num_labels,
3036 : labels);
3037 : }
3038 :
3039 0 : return nh;
3040 : }
3041 :
3042 0 : static int netlink_nexthop_process_group(struct rtattr **tb,
3043 : struct nh_grp *z_grp, int z_grp_size,
3044 : struct nhg_resilience *nhgr)
3045 : {
3046 0 : uint8_t count = 0;
3047 : /* linux/nexthop.h group struct */
3048 0 : struct nexthop_grp *n_grp = NULL;
3049 :
3050 0 : n_grp = (struct nexthop_grp *)RTA_DATA(tb[NHA_GROUP]);
3051 0 : count = (RTA_PAYLOAD(tb[NHA_GROUP]) / sizeof(*n_grp));
3052 :
3053 0 : if (!count || (count * sizeof(*n_grp)) != RTA_PAYLOAD(tb[NHA_GROUP])) {
3054 0 : flog_warn(EC_ZEBRA_BAD_NHG_MESSAGE,
3055 : "Invalid nexthop group received from the kernel");
3056 0 : return count;
3057 : }
3058 :
3059 0 : for (int i = 0; ((i < count) && (i < z_grp_size)); i++) {
3060 0 : z_grp[i].id = n_grp[i].id;
3061 0 : z_grp[i].weight = n_grp[i].weight + 1;
3062 : }
3063 :
3064 0 : memset(nhgr, 0, sizeof(*nhgr));
3065 0 : if (tb[NHA_RES_GROUP]) {
3066 0 : struct rtattr *tbn[NHA_RES_GROUP_MAX + 1];
3067 0 : struct rtattr *rta;
3068 0 : struct rtattr *res_group = tb[NHA_RES_GROUP];
3069 :
3070 0 : netlink_parse_rtattr_nested(tbn, NHA_RES_GROUP_MAX, res_group);
3071 :
3072 0 : if (tbn[NHA_RES_GROUP_BUCKETS]) {
3073 0 : rta = tbn[NHA_RES_GROUP_BUCKETS];
3074 0 : nhgr->buckets = *(uint16_t *)RTA_DATA(rta);
3075 : }
3076 :
3077 0 : if (tbn[NHA_RES_GROUP_IDLE_TIMER]) {
3078 0 : rta = tbn[NHA_RES_GROUP_IDLE_TIMER];
3079 0 : nhgr->idle_timer = *(uint32_t *)RTA_DATA(rta);
3080 : }
3081 :
3082 0 : if (tbn[NHA_RES_GROUP_UNBALANCED_TIMER]) {
3083 0 : rta = tbn[NHA_RES_GROUP_UNBALANCED_TIMER];
3084 0 : nhgr->unbalanced_timer = *(uint32_t *)RTA_DATA(rta);
3085 : }
3086 :
3087 0 : if (tbn[NHA_RES_GROUP_UNBALANCED_TIME]) {
3088 0 : rta = tbn[NHA_RES_GROUP_UNBALANCED_TIME];
3089 0 : nhgr->unbalanced_time = *(uint64_t *)RTA_DATA(rta);
3090 : }
3091 : }
3092 :
3093 : return count;
3094 : }
3095 :
3096 : /**
3097 : * netlink_nexthop_change() - Read in change about nexthops from the kernel
3098 : *
3099 : * @h: Netlink message header
3100 : * @ns_id: Namspace id
3101 : * @startup: Are we reading under startup conditions?
3102 : *
3103 : * Return: Result status
3104 : */
3105 0 : int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
3106 : {
3107 0 : int len;
3108 : /* nexthop group id */
3109 0 : uint32_t id;
3110 0 : unsigned char family;
3111 0 : int type;
3112 0 : afi_t afi = AFI_UNSPEC;
3113 0 : vrf_id_t vrf_id = VRF_DEFAULT;
3114 0 : struct interface *ifp = NULL;
3115 0 : struct nhmsg *nhm = NULL;
3116 0 : struct nexthop nh = {};
3117 0 : struct nh_grp grp[MULTIPATH_NUM] = {};
3118 : /* Count of nexthops in group array */
3119 0 : uint8_t grp_count = 0;
3120 0 : struct rtattr *tb[NHA_MAX + 1] = {};
3121 :
3122 0 : frrtrace(3, frr_zebra, netlink_nexthop_change, h, ns_id, startup);
3123 :
3124 0 : nhm = NLMSG_DATA(h);
3125 :
3126 0 : if (ns_id)
3127 : vrf_id = ns_id;
3128 :
3129 0 : if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
3130 : return 0;
3131 :
3132 0 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct nhmsg));
3133 0 : if (len < 0) {
3134 0 : zlog_warn(
3135 : "%s: Message received from netlink is of a broken size %d %zu",
3136 : __func__, h->nlmsg_len,
3137 : (size_t)NLMSG_LENGTH(sizeof(struct nhmsg)));
3138 0 : return -1;
3139 : }
3140 :
3141 0 : netlink_parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len,
3142 : NLA_F_NESTED);
3143 :
3144 :
3145 0 : if (!tb[NHA_ID]) {
3146 0 : flog_warn(
3147 : EC_ZEBRA_BAD_NHG_MESSAGE,
3148 : "Nexthop group without an ID received from the kernel");
3149 0 : return -1;
3150 : }
3151 :
3152 : /* We use the ID key'd nhg table for kernel updates */
3153 0 : id = *((uint32_t *)RTA_DATA(tb[NHA_ID]));
3154 :
3155 0 : if (zebra_evpn_mh_is_fdb_nh(id)) {
3156 : /* If this is a L2 NH just ignore it */
3157 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
3158 0 : zlog_debug("Ignore kernel update (%u) for fdb-nh 0x%x",
3159 : h->nlmsg_type, id);
3160 : }
3161 0 : return 0;
3162 : }
3163 :
3164 0 : family = nhm->nh_family;
3165 0 : afi = family2afi(family);
3166 :
3167 0 : type = proto2zebra(nhm->nh_protocol, 0, true);
3168 :
3169 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3170 0 : zlog_debug("%s ID (%u) %s NS %u",
3171 : nl_msg_type_to_str(h->nlmsg_type), id,
3172 : nl_family_to_str(family), ns_id);
3173 :
3174 :
3175 0 : if (h->nlmsg_type == RTM_NEWNEXTHOP) {
3176 0 : struct nhg_resilience nhgr = {};
3177 :
3178 0 : if (tb[NHA_GROUP]) {
3179 : /**
3180 : * If this is a group message its only going to have
3181 : * an array of nexthop IDs associated with it
3182 : */
3183 0 : grp_count = netlink_nexthop_process_group(
3184 : tb, grp, array_size(grp), &nhgr);
3185 : } else {
3186 0 : if (tb[NHA_BLACKHOLE]) {
3187 : /**
3188 : * This nexthop is just for blackhole-ing
3189 : * traffic, it should not have an OIF, GATEWAY,
3190 : * or ENCAP
3191 : */
3192 0 : nh.type = NEXTHOP_TYPE_BLACKHOLE;
3193 0 : nh.bh_type = BLACKHOLE_UNSPEC;
3194 0 : } else if (tb[NHA_OIF])
3195 : /**
3196 : * This is a true new nexthop, so we need
3197 : * to parse the gateway and device info
3198 : */
3199 0 : nh = netlink_nexthop_process_nh(tb, family,
3200 : &ifp, ns_id);
3201 : else {
3202 :
3203 0 : flog_warn(
3204 : EC_ZEBRA_BAD_NHG_MESSAGE,
3205 : "Invalid Nexthop message received from the kernel with ID (%u)",
3206 : id);
3207 0 : return -1;
3208 : }
3209 0 : SET_FLAG(nh.flags, NEXTHOP_FLAG_ACTIVE);
3210 0 : if (nhm->nh_flags & RTNH_F_ONLINK)
3211 0 : SET_FLAG(nh.flags, NEXTHOP_FLAG_ONLINK);
3212 0 : vrf_id = nh.vrf_id;
3213 : }
3214 :
3215 0 : if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi,
3216 : type, startup, &nhgr))
3217 : return -1;
3218 :
3219 0 : } else if (h->nlmsg_type == RTM_DELNEXTHOP)
3220 0 : zebra_nhg_kernel_del(id, vrf_id);
3221 :
3222 : return 0;
3223 : }
3224 :
3225 : /**
3226 : * netlink_request_nexthop() - Request nextop information from the kernel
3227 : * @zns: Zebra namespace
3228 : * @family: AF_* netlink family
3229 : * @type: RTM_* route type
3230 : *
3231 : * Return: Result status
3232 : */
3233 1 : static int netlink_request_nexthop(struct zebra_ns *zns, int family, int type)
3234 : {
3235 1 : struct {
3236 : struct nlmsghdr n;
3237 : struct nhmsg nhm;
3238 : } req;
3239 :
3240 : /* Form the request, specifying filter (rtattr) if needed. */
3241 1 : memset(&req, 0, sizeof(req));
3242 1 : req.n.nlmsg_type = type;
3243 1 : req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
3244 1 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
3245 1 : req.nhm.nh_family = family;
3246 :
3247 1 : return netlink_request(&zns->netlink_cmd, &req);
3248 : }
3249 :
3250 :
3251 : /**
3252 : * netlink_nexthop_read() - Nexthop read function using netlink interface
3253 : *
3254 : * @zns: Zebra name space
3255 : *
3256 : * Return: Result status
3257 : * Only called at bootstrap time.
3258 : */
3259 1 : int netlink_nexthop_read(struct zebra_ns *zns)
3260 : {
3261 1 : int ret;
3262 1 : struct zebra_dplane_info dp_info;
3263 :
3264 1 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
3265 :
3266 : /* Get nexthop objects */
3267 1 : ret = netlink_request_nexthop(zns, AF_UNSPEC, RTM_GETNEXTHOP);
3268 1 : if (ret < 0)
3269 : return ret;
3270 1 : ret = netlink_parse_info(netlink_nexthop_change, &zns->netlink_cmd,
3271 : &dp_info, 0, true);
3272 :
3273 1 : if (!ret)
3274 : /* If we succesfully read in nexthop objects,
3275 : * this kernel must support them.
3276 : */
3277 1 : supports_nh = true;
3278 1 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_NHG)
3279 0 : zlog_debug("Nexthop objects %ssupported on this kernel",
3280 : supports_nh ? "" : "not ");
3281 :
3282 1 : zebra_router_set_supports_nhgs(supports_nh);
3283 :
3284 1 : return ret;
3285 : }
3286 :
3287 :
3288 0 : int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen,
3289 : ns_id_t ns_id, uint8_t family, bool permanent)
3290 : {
3291 0 : return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex,
3292 : addr, lla, llalen, ns_id, family, permanent,
3293 : RTPROT_ZEBRA);
3294 : }
3295 :
3296 : /**
3297 : * netlink_neigh_update_msg_encode() - Common helper api for encoding
3298 : * evpn neighbor update as netlink messages using dataplane context object.
3299 : * Here, a neighbor refers to a bridge forwarding database entry for
3300 : * either unicast forwarding or head-end replication or an IP neighbor
3301 : * entry.
3302 : * @ctx: Dataplane context
3303 : * @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
3304 : * @lla: A pointer to neighbor cache link layer address
3305 : * @llalen: Length of the pointer to neighbor cache link layer
3306 : * address
3307 : * @ip: A neighbor cache n/w layer destination address
3308 : * In the case of bridge FDB, this represnts the remote
3309 : * VTEP IP.
3310 : * @replace_obj: Whether NEW request should replace existing object or
3311 : * add to the end of the list
3312 : * @family: AF_* netlink family
3313 : * @type: RTN_* route type
3314 : * @flags: NTF_* flags
3315 : * @state: NUD_* states
3316 : * @data: data buffer pointer
3317 : * @datalen: total amount of data buffer space
3318 : * @protocol: protocol information
3319 : *
3320 : * Return: 0 when the msg doesn't fit entirely in the buffer
3321 : * otherwise the number of bytes written to buf.
3322 : */
3323 0 : static ssize_t netlink_neigh_update_msg_encode(
3324 : const struct zebra_dplane_ctx *ctx, int cmd, const void *lla,
3325 : int llalen, const struct ipaddr *ip, bool replace_obj, uint8_t family,
3326 : uint8_t type, uint8_t flags, uint16_t state, uint32_t nhg_id, bool nfy,
3327 : uint8_t nfy_flags, bool ext, uint32_t ext_flags, void *data,
3328 : size_t datalen, uint8_t protocol)
3329 : {
3330 0 : struct {
3331 : struct nlmsghdr n;
3332 : struct ndmsg ndm;
3333 : char buf[];
3334 0 : } *req = data;
3335 0 : int ipa_len;
3336 0 : enum dplane_op_e op;
3337 :
3338 0 : if (datalen < sizeof(*req))
3339 : return 0;
3340 0 : memset(req, 0, sizeof(*req));
3341 :
3342 0 : op = dplane_ctx_get_op(ctx);
3343 :
3344 0 : req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
3345 0 : req->n.nlmsg_flags = NLM_F_REQUEST;
3346 0 : if (cmd == RTM_NEWNEIGH)
3347 0 : req->n.nlmsg_flags |=
3348 : NLM_F_CREATE
3349 : | (replace_obj ? NLM_F_REPLACE : NLM_F_APPEND);
3350 0 : req->n.nlmsg_type = cmd;
3351 0 : req->ndm.ndm_family = family;
3352 0 : req->ndm.ndm_type = type;
3353 0 : req->ndm.ndm_state = state;
3354 0 : req->ndm.ndm_flags = flags;
3355 0 : req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx);
3356 :
3357 0 : if (!nl_attr_put(&req->n, datalen, NDA_PROTOCOL, &protocol,
3358 : sizeof(protocol)))
3359 : return 0;
3360 :
3361 0 : if (lla) {
3362 0 : if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, lla, llalen))
3363 : return 0;
3364 : }
3365 :
3366 0 : if (nfy) {
3367 0 : struct rtattr *nest;
3368 :
3369 0 : nest = nl_attr_nest(&req->n, datalen,
3370 : NDA_FDB_EXT_ATTRS | NLA_F_NESTED);
3371 0 : if (!nest)
3372 : return 0;
3373 :
3374 0 : if (!nl_attr_put(&req->n, datalen, NFEA_ACTIVITY_NOTIFY,
3375 : &nfy_flags, sizeof(nfy_flags)))
3376 : return 0;
3377 0 : if (!nl_attr_put(&req->n, datalen, NFEA_DONT_REFRESH, NULL, 0))
3378 : return 0;
3379 :
3380 0 : nl_attr_nest_end(&req->n, nest);
3381 : }
3382 :
3383 :
3384 0 : if (ext) {
3385 0 : if (!nl_attr_put(&req->n, datalen, NDA_EXT_FLAGS, &ext_flags,
3386 : sizeof(ext_flags)))
3387 : return 0;
3388 : }
3389 :
3390 0 : if (nhg_id) {
3391 0 : if (!nl_attr_put32(&req->n, datalen, NDA_NH_ID, nhg_id))
3392 : return 0;
3393 : } else {
3394 0 : ipa_len =
3395 0 : IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN;
3396 0 : if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr,
3397 : ipa_len))
3398 : return 0;
3399 : }
3400 :
3401 0 : if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) {
3402 0 : vlanid_t vid = dplane_ctx_mac_get_vlan(ctx);
3403 :
3404 0 : if (vid > 0) {
3405 0 : if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid))
3406 : return 0;
3407 : }
3408 :
3409 0 : if (!nl_attr_put32(&req->n, datalen, NDA_MASTER,
3410 0 : dplane_ctx_mac_get_br_ifindex(ctx)))
3411 : return 0;
3412 : }
3413 :
3414 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
3415 : }
3416 :
3417 : /*
3418 : * Add remote VTEP to the flood list for this VxLAN interface (VNI). This
3419 : * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00.
3420 : */
3421 : static ssize_t
3422 0 : netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, int cmd,
3423 : void *buf, size_t buflen)
3424 : {
3425 0 : struct ethaddr dst_mac = {.octet = {0}};
3426 0 : int proto = RTPROT_ZEBRA;
3427 :
3428 0 : if (dplane_ctx_get_type(ctx) != 0)
3429 0 : proto = zebra2proto(dplane_ctx_get_type(ctx));
3430 :
3431 0 : return netlink_neigh_update_msg_encode(
3432 : ctx, cmd, (const void *)&dst_mac, ETH_ALEN,
3433 : dplane_ctx_neigh_get_ipaddr(ctx), false, PF_BRIDGE, 0, NTF_SELF,
3434 : (NUD_NOARP | NUD_PERMANENT), 0 /*nhg*/, false /*nfy*/,
3435 : 0 /*nfy_flags*/, false /*ext*/, 0 /*ext_flags*/, buf, buflen,
3436 : proto);
3437 : }
3438 :
3439 : #ifndef NDA_RTA
3440 : #define NDA_RTA(r) \
3441 : ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
3442 : #endif
3443 :
3444 0 : static int netlink_macfdb_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
3445 : {
3446 0 : struct ndmsg *ndm;
3447 0 : struct interface *ifp;
3448 0 : struct zebra_if *zif;
3449 0 : struct rtattr *tb[NDA_MAX + 1];
3450 0 : struct interface *br_if;
3451 0 : struct ethaddr mac;
3452 0 : vlanid_t vid = 0;
3453 0 : struct in_addr vtep_ip;
3454 0 : int vid_present = 0, dst_present = 0;
3455 0 : char vid_buf[20];
3456 0 : char dst_buf[30];
3457 0 : bool sticky;
3458 0 : bool local_inactive = false;
3459 0 : bool dp_static = false;
3460 0 : uint32_t nhg_id = 0;
3461 :
3462 0 : ndm = NLMSG_DATA(h);
3463 :
3464 : /* We only process macfdb notifications if EVPN is enabled */
3465 0 : if (!is_evpn_enabled())
3466 : return 0;
3467 :
3468 : /* Parse attributes and extract fields of interest. Do basic
3469 : * validation of the fields.
3470 : */
3471 0 : netlink_parse_rtattr_flags(tb, NDA_MAX, NDA_RTA(ndm), len,
3472 : NLA_F_NESTED);
3473 :
3474 0 : if (!tb[NDA_LLADDR]) {
3475 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3476 0 : zlog_debug("%s AF_BRIDGE IF %u - no LLADDR",
3477 : nl_msg_type_to_str(h->nlmsg_type),
3478 : ndm->ndm_ifindex);
3479 0 : return 0;
3480 : }
3481 :
3482 0 : if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
3483 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3484 0 : zlog_debug(
3485 : "%s AF_BRIDGE IF %u - LLADDR is not MAC, len %lu",
3486 : nl_msg_type_to_str(h->nlmsg_type), ndm->ndm_ifindex,
3487 : (unsigned long)RTA_PAYLOAD(tb[NDA_LLADDR]));
3488 0 : return 0;
3489 : }
3490 :
3491 0 : memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
3492 :
3493 0 : if (tb[NDA_VLAN]) {
3494 0 : vid_present = 1;
3495 0 : vid = *(uint16_t *)RTA_DATA(tb[NDA_VLAN]);
3496 0 : snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
3497 : }
3498 :
3499 0 : if (tb[NDA_DST]) {
3500 : /* TODO: Only IPv4 supported now. */
3501 0 : dst_present = 1;
3502 0 : memcpy(&vtep_ip.s_addr, RTA_DATA(tb[NDA_DST]),
3503 : IPV4_MAX_BYTELEN);
3504 0 : snprintfrr(dst_buf, sizeof(dst_buf), " dst %pI4",
3505 : &vtep_ip);
3506 : }
3507 :
3508 0 : if (tb[NDA_NH_ID])
3509 0 : nhg_id = *(uint32_t *)RTA_DATA(tb[NDA_NH_ID]);
3510 :
3511 0 : if (ndm->ndm_state & NUD_STALE)
3512 0 : local_inactive = true;
3513 :
3514 0 : if (tb[NDA_FDB_EXT_ATTRS]) {
3515 0 : struct rtattr *attr = tb[NDA_FDB_EXT_ATTRS];
3516 0 : struct rtattr *nfea_tb[NFEA_MAX + 1] = {0};
3517 :
3518 0 : netlink_parse_rtattr_nested(nfea_tb, NFEA_MAX, attr);
3519 0 : if (nfea_tb[NFEA_ACTIVITY_NOTIFY]) {
3520 0 : uint8_t nfy_flags;
3521 :
3522 0 : nfy_flags = *(uint8_t *)RTA_DATA(
3523 : nfea_tb[NFEA_ACTIVITY_NOTIFY]);
3524 0 : if (nfy_flags & FDB_NOTIFY_BIT)
3525 0 : dp_static = true;
3526 0 : if (nfy_flags & FDB_NOTIFY_INACTIVE_BIT)
3527 0 : local_inactive = true;
3528 : }
3529 : }
3530 :
3531 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3532 0 : zlog_debug("Rx %s AF_BRIDGE IF %u%s st 0x%x fl 0x%x MAC %pEA%s nhg %d",
3533 : nl_msg_type_to_str(h->nlmsg_type),
3534 : ndm->ndm_ifindex, vid_present ? vid_buf : "",
3535 : ndm->ndm_state, ndm->ndm_flags, &mac,
3536 : dst_present ? dst_buf : "", nhg_id);
3537 :
3538 : /* The interface should exist. */
3539 0 : ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
3540 0 : ndm->ndm_ifindex);
3541 0 : if (!ifp || !ifp->info)
3542 : return 0;
3543 :
3544 : /* The interface should be something we're interested in. */
3545 0 : if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
3546 : return 0;
3547 :
3548 0 : zif = (struct zebra_if *)ifp->info;
3549 0 : if ((br_if = zif->brslave_info.br_if) == NULL) {
3550 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3551 0 : zlog_debug(
3552 : "%s AF_BRIDGE IF %s(%u) brIF %u - no bridge master",
3553 : nl_msg_type_to_str(h->nlmsg_type), ifp->name,
3554 : ndm->ndm_ifindex,
3555 : zif->brslave_info.bridge_ifindex);
3556 0 : return 0;
3557 : }
3558 :
3559 0 : sticky = !!(ndm->ndm_flags & NTF_STICKY);
3560 :
3561 0 : if (filter_vlan && vid != filter_vlan) {
3562 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3563 0 : zlog_debug(" Filtered due to filter vlan: %d",
3564 : filter_vlan);
3565 0 : return 0;
3566 : }
3567 :
3568 : /* If add or update, do accordingly if learnt on a "local" interface; if
3569 : * the notification is over VxLAN, this has to be related to
3570 : * multi-homing,
3571 : * so perform an implicit delete of any local entry (if it exists).
3572 : */
3573 0 : if (h->nlmsg_type == RTM_NEWNEIGH) {
3574 : /* Drop "permanent" entries. */
3575 0 : if (ndm->ndm_state & NUD_PERMANENT) {
3576 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3577 0 : zlog_debug(
3578 : " Dropping entry because of NUD_PERMANENT");
3579 0 : return 0;
3580 : }
3581 :
3582 0 : if (IS_ZEBRA_IF_VXLAN(ifp))
3583 0 : return zebra_vxlan_dp_network_mac_add(
3584 : ifp, br_if, &mac, vid, nhg_id, sticky,
3585 : !!(ndm->ndm_flags & NTF_EXT_LEARNED));
3586 :
3587 0 : return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid,
3588 : sticky, local_inactive, dp_static);
3589 : }
3590 :
3591 : /* This is a delete notification.
3592 : * Ignore the notification with IP dest as it may just signify that the
3593 : * MAC has moved from remote to local. The exception is the special
3594 : * all-zeros MAC that represents the BUM flooding entry; we may have
3595 : * to readd it. Otherwise,
3596 : * 1. For a MAC over VxLan, check if it needs to be refreshed(readded)
3597 : * 2. For a MAC over "local" interface, delete the mac
3598 : * Note: We will get notifications from both bridge driver and VxLAN
3599 : * driver.
3600 : */
3601 0 : if (nhg_id)
3602 : return 0;
3603 :
3604 0 : if (dst_present) {
3605 0 : u_char zero_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
3606 :
3607 0 : if (!memcmp(zero_mac, mac.octet, ETH_ALEN))
3608 0 : return zebra_vxlan_check_readd_vtep(ifp, vtep_ip);
3609 : return 0;
3610 : }
3611 :
3612 0 : if (IS_ZEBRA_IF_VXLAN(ifp))
3613 0 : return zebra_vxlan_dp_network_mac_del(ifp, br_if, &mac, vid);
3614 :
3615 0 : return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid);
3616 : }
3617 :
3618 0 : static int netlink_macfdb_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
3619 : {
3620 0 : int len;
3621 0 : struct ndmsg *ndm;
3622 :
3623 0 : if (h->nlmsg_type != RTM_NEWNEIGH)
3624 : return 0;
3625 :
3626 : /* Length validity. */
3627 0 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
3628 0 : if (len < 0)
3629 : return -1;
3630 :
3631 : /* We are interested only in AF_BRIDGE notifications. */
3632 0 : ndm = NLMSG_DATA(h);
3633 0 : if (ndm->ndm_family != AF_BRIDGE)
3634 : return 0;
3635 :
3636 0 : return netlink_macfdb_change(h, len, ns_id);
3637 : }
3638 :
3639 : /* Request for MAC FDB information from the kernel */
3640 0 : static int netlink_request_macs(struct nlsock *netlink_cmd, int family,
3641 : int type, ifindex_t master_ifindex)
3642 : {
3643 0 : struct {
3644 : struct nlmsghdr n;
3645 : struct ifinfomsg ifm;
3646 : char buf[256];
3647 : } req;
3648 :
3649 : /* Form the request, specifying filter (rtattr) if needed. */
3650 0 : memset(&req, 0, sizeof(req));
3651 0 : req.n.nlmsg_type = type;
3652 0 : req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
3653 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
3654 0 : req.ifm.ifi_family = family;
3655 0 : if (master_ifindex)
3656 0 : nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex);
3657 :
3658 0 : return netlink_request(netlink_cmd, &req);
3659 : }
3660 :
3661 : /*
3662 : * MAC forwarding database read using netlink interface. This is invoked
3663 : * at startup.
3664 : */
3665 0 : int netlink_macfdb_read(struct zebra_ns *zns)
3666 : {
3667 0 : int ret;
3668 0 : struct zebra_dplane_info dp_info;
3669 :
3670 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
3671 :
3672 : /* Get bridge FDB table. */
3673 0 : ret = netlink_request_macs(&zns->netlink_cmd, AF_BRIDGE, RTM_GETNEIGH,
3674 : 0);
3675 0 : if (ret < 0)
3676 : return ret;
3677 : /* We are reading entire table. */
3678 0 : filter_vlan = 0;
3679 0 : ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
3680 : &dp_info, 0, true);
3681 :
3682 0 : return ret;
3683 : }
3684 :
3685 : /*
3686 : * MAC forwarding database read using netlink interface. This is for a
3687 : * specific bridge and matching specific access VLAN (if VLAN-aware bridge).
3688 : */
3689 0 : int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp,
3690 : struct interface *br_if)
3691 : {
3692 0 : struct zebra_if *br_zif;
3693 0 : struct zebra_if *zif;
3694 0 : struct zebra_l2info_vxlan *vxl;
3695 0 : struct zebra_dplane_info dp_info;
3696 0 : int ret = 0;
3697 :
3698 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
3699 :
3700 : /* Save VLAN we're filtering on, if needed. */
3701 0 : br_zif = (struct zebra_if *)br_if->info;
3702 0 : zif = (struct zebra_if *)ifp->info;
3703 0 : vxl = &zif->l2info.vxl;
3704 0 : if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif))
3705 0 : filter_vlan = vxl->access_vlan;
3706 :
3707 : /* Get bridge FDB table for specific bridge - we do the VLAN filtering.
3708 : */
3709 0 : ret = netlink_request_macs(&zns->netlink_cmd, AF_BRIDGE, RTM_GETNEIGH,
3710 : br_if->ifindex);
3711 0 : if (ret < 0)
3712 : return ret;
3713 0 : ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
3714 : &dp_info, 0, false);
3715 :
3716 : /* Reset VLAN filter. */
3717 0 : filter_vlan = 0;
3718 0 : return ret;
3719 : }
3720 :
3721 :
3722 : /* Request for MAC FDB for a specific MAC address in VLAN from the kernel */
3723 0 : static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns,
3724 : int family, int type,
3725 : struct interface *br_if,
3726 : const struct ethaddr *mac,
3727 : vlanid_t vid)
3728 : {
3729 0 : struct {
3730 : struct nlmsghdr n;
3731 : struct ndmsg ndm;
3732 : char buf[256];
3733 : } req;
3734 0 : struct zebra_if *br_zif;
3735 :
3736 0 : memset(&req, 0, sizeof(req));
3737 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
3738 0 : req.n.nlmsg_type = type; /* RTM_GETNEIGH */
3739 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
3740 0 : req.ndm.ndm_family = family; /* AF_BRIDGE */
3741 : /* req.ndm.ndm_state = NUD_REACHABLE; */
3742 :
3743 0 : nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6);
3744 :
3745 0 : br_zif = (struct zebra_if *)br_if->info;
3746 0 : if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0)
3747 0 : nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid);
3748 :
3749 0 : nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex);
3750 :
3751 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3752 0 : zlog_debug(
3753 : "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u",
3754 : __func__, nl_family_to_str(req.ndm.ndm_family),
3755 : br_if->name, br_if->ifindex, br_if->vrf->name,
3756 : br_if->vrf->vrf_id, mac, vid);
3757 :
3758 0 : return netlink_request(&zns->netlink_cmd, &req);
3759 : }
3760 :
3761 0 : int netlink_macfdb_read_specific_mac(struct zebra_ns *zns,
3762 : struct interface *br_if,
3763 : const struct ethaddr *mac, vlanid_t vid)
3764 : {
3765 0 : int ret = 0;
3766 0 : struct zebra_dplane_info dp_info;
3767 :
3768 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
3769 :
3770 : /* Get bridge FDB table for specific bridge - we do the VLAN filtering.
3771 : */
3772 0 : ret = netlink_request_specific_mac_in_bridge(zns, AF_BRIDGE,
3773 : RTM_GETNEIGH,
3774 : br_if, mac, vid);
3775 0 : if (ret < 0)
3776 : return ret;
3777 :
3778 0 : ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd,
3779 : &dp_info, 1, false);
3780 :
3781 0 : return ret;
3782 : }
3783 :
3784 : /*
3785 : * Netlink-specific handler for MAC updates using dataplane context object.
3786 : */
3787 0 : ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, void *data,
3788 : size_t datalen)
3789 : {
3790 0 : struct ipaddr vtep_ip;
3791 0 : vlanid_t vid;
3792 0 : ssize_t total;
3793 0 : int cmd;
3794 0 : uint8_t flags;
3795 0 : uint16_t state;
3796 0 : uint32_t nhg_id;
3797 0 : uint32_t update_flags;
3798 0 : bool nfy = false;
3799 0 : uint8_t nfy_flags = 0;
3800 0 : int proto = RTPROT_ZEBRA;
3801 :
3802 0 : if (dplane_ctx_get_type(ctx) != 0)
3803 0 : proto = zebra2proto(dplane_ctx_get_type(ctx));
3804 :
3805 0 : cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
3806 0 : ? RTM_NEWNEIGH : RTM_DELNEIGH;
3807 :
3808 0 : flags = NTF_MASTER;
3809 0 : state = NUD_REACHABLE;
3810 :
3811 0 : update_flags = dplane_ctx_mac_get_update_flags(ctx);
3812 0 : if (update_flags & DPLANE_MAC_REMOTE) {
3813 0 : flags |= NTF_SELF;
3814 0 : if (dplane_ctx_mac_is_sticky(ctx)) {
3815 : /* NUD_NOARP prevents the entry from expiring */
3816 : state |= NUD_NOARP;
3817 : /* sticky the entry from moving */
3818 : flags |= NTF_STICKY;
3819 : } else {
3820 0 : flags |= NTF_EXT_LEARNED;
3821 : }
3822 : /* if it was static-local previously we need to clear the
3823 : * notify flags on replace with remote
3824 : */
3825 0 : if (update_flags & DPLANE_MAC_WAS_STATIC)
3826 0 : nfy = true;
3827 : } else {
3828 : /* local mac */
3829 0 : if (update_flags & DPLANE_MAC_SET_STATIC) {
3830 0 : nfy_flags |= FDB_NOTIFY_BIT;
3831 0 : state |= NUD_NOARP;
3832 : }
3833 :
3834 0 : if (update_flags & DPLANE_MAC_SET_INACTIVE)
3835 0 : nfy_flags |= FDB_NOTIFY_INACTIVE_BIT;
3836 :
3837 : nfy = true;
3838 : }
3839 :
3840 0 : nhg_id = dplane_ctx_mac_get_nhg_id(ctx);
3841 0 : vtep_ip.ipaddr_v4 = *(dplane_ctx_mac_get_vtep_ip(ctx));
3842 0 : SET_IPADDR_V4(&vtep_ip);
3843 :
3844 0 : if (IS_ZEBRA_DEBUG_KERNEL) {
3845 0 : char vid_buf[20];
3846 0 : const struct ethaddr *mac = dplane_ctx_mac_get_addr(ctx);
3847 :
3848 0 : vid = dplane_ctx_mac_get_vlan(ctx);
3849 0 : if (vid > 0)
3850 0 : snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid);
3851 : else
3852 0 : vid_buf[0] = '\0';
3853 :
3854 0 : zlog_debug(
3855 : "Tx %s family %s IF %s(%u)%s %sMAC %pEA dst %pIA nhg %u%s%s%s%s%s",
3856 : nl_msg_type_to_str(cmd), nl_family_to_str(AF_BRIDGE),
3857 : dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
3858 : vid_buf, dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "",
3859 : mac, &vtep_ip, nhg_id,
3860 : (update_flags & DPLANE_MAC_REMOTE) ? " rem" : "",
3861 : (update_flags & DPLANE_MAC_WAS_STATIC) ? " clr_sync"
3862 : : "",
3863 : (update_flags & DPLANE_MAC_SET_STATIC) ? " static" : "",
3864 : (update_flags & DPLANE_MAC_SET_INACTIVE) ? " inactive"
3865 : : "",
3866 : nfy ? " nfy" : "");
3867 : }
3868 :
3869 0 : total = netlink_neigh_update_msg_encode(
3870 0 : ctx, cmd, (const void *)dplane_ctx_mac_get_addr(ctx), ETH_ALEN,
3871 : &vtep_ip, true, AF_BRIDGE, 0, flags, state, nhg_id, nfy,
3872 : nfy_flags, false /*ext*/, 0 /*ext_flags*/, data, datalen,
3873 : proto);
3874 :
3875 0 : return total;
3876 : }
3877 :
3878 : /*
3879 : * In the event the kernel deletes ipv4 link-local neighbor entries created for
3880 : * 5549 support, re-install them.
3881 : */
3882 0 : static void netlink_handle_5549(struct ndmsg *ndm, struct zebra_if *zif,
3883 : struct interface *ifp, struct ipaddr *ip,
3884 : bool handle_failed)
3885 : {
3886 0 : if (ndm->ndm_family != AF_INET)
3887 : return;
3888 :
3889 0 : if (!zif->v6_2_v4_ll_neigh_entry)
3890 : return;
3891 :
3892 0 : if (ipv4_ll.s_addr != ip->ip._v4_addr.s_addr)
3893 : return;
3894 :
3895 0 : if (handle_failed && ndm->ndm_state & NUD_FAILED) {
3896 0 : zlog_info("Neighbor Entry for %s has entered a failed state, not reinstalling",
3897 : ifp->name);
3898 0 : return;
3899 : }
3900 :
3901 0 : if_nbr_ipv6ll_to_ipv4ll_neigh_update(ifp, &zif->v6_2_v4_ll_addr6, true);
3902 : }
3903 :
3904 : #define NUD_VALID \
3905 : (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \
3906 : | NUD_DELAY)
3907 : #define NUD_LOCAL_ACTIVE \
3908 : (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)
3909 :
3910 : static int netlink_nbr_entry_state_to_zclient(int nbr_state)
3911 : {
3912 : /* an exact match is done between
3913 : * - netlink neighbor state values: NDM_XXX (see in linux/neighbour.h)
3914 : * - zclient neighbor state values: ZEBRA_NEIGH_STATE_XXX
3915 : * (see in lib/zclient.h)
3916 : */
3917 : return nbr_state;
3918 : }
3919 0 : static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id)
3920 : {
3921 0 : struct ndmsg *ndm;
3922 0 : struct interface *ifp;
3923 0 : struct zebra_if *zif;
3924 0 : struct rtattr *tb[NDA_MAX + 1];
3925 0 : struct interface *link_if;
3926 0 : struct ethaddr mac;
3927 0 : struct ipaddr ip;
3928 0 : char buf[ETHER_ADDR_STRLEN];
3929 0 : int mac_present = 0;
3930 0 : bool is_ext;
3931 0 : bool is_router;
3932 0 : bool local_inactive;
3933 0 : uint32_t ext_flags = 0;
3934 0 : bool dp_static = false;
3935 0 : int l2_len = 0;
3936 0 : int cmd;
3937 :
3938 0 : ndm = NLMSG_DATA(h);
3939 :
3940 : /* The interface should exist. */
3941 0 : ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
3942 0 : ndm->ndm_ifindex);
3943 0 : if (!ifp || !ifp->info)
3944 : return 0;
3945 :
3946 0 : zif = (struct zebra_if *)ifp->info;
3947 :
3948 : /* Parse attributes and extract fields of interest. */
3949 0 : netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len);
3950 :
3951 0 : if (!tb[NDA_DST]) {
3952 0 : zlog_debug("%s family %s IF %s(%u) vrf %s(%u) - no DST",
3953 : nl_msg_type_to_str(h->nlmsg_type),
3954 : nl_family_to_str(ndm->ndm_family), ifp->name,
3955 : ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id);
3956 0 : return 0;
3957 : }
3958 :
3959 0 : memset(&ip, 0, sizeof(ip));
3960 0 : ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6;
3961 0 : memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
3962 :
3963 : /* if kernel deletes our rfc5549 neighbor entry, re-install it */
3964 0 : if (h->nlmsg_type == RTM_DELNEIGH && (ndm->ndm_state & NUD_PERMANENT)) {
3965 0 : netlink_handle_5549(ndm, zif, ifp, &ip, false);
3966 0 : if (IS_ZEBRA_DEBUG_KERNEL)
3967 0 : zlog_debug(
3968 : " Neighbor Entry Received is a 5549 entry, finished");
3969 0 : return 0;
3970 : }
3971 :
3972 : /* if kernel marks our rfc5549 neighbor entry invalid, re-install it */
3973 0 : if (h->nlmsg_type == RTM_NEWNEIGH && !(ndm->ndm_state & NUD_VALID))
3974 0 : netlink_handle_5549(ndm, zif, ifp, &ip, true);
3975 :
3976 : /* we send link layer information to client:
3977 : * - nlmsg_type = RTM_DELNEIGH|NEWNEIGH|GETNEIGH
3978 : * - struct ipaddr ( for DEL and GET)
3979 : * - struct ethaddr mac; (for NEW)
3980 : */
3981 0 : if (h->nlmsg_type == RTM_NEWNEIGH)
3982 : cmd = ZEBRA_NHRP_NEIGH_ADDED;
3983 0 : else if (h->nlmsg_type == RTM_GETNEIGH)
3984 : cmd = ZEBRA_NHRP_NEIGH_GET;
3985 0 : else if (h->nlmsg_type == RTM_DELNEIGH)
3986 : cmd = ZEBRA_NHRP_NEIGH_REMOVED;
3987 : else {
3988 0 : zlog_debug("%s(): unknown nlmsg type %u", __func__,
3989 : h->nlmsg_type);
3990 0 : return 0;
3991 : }
3992 0 : if (tb[NDA_LLADDR]) {
3993 : /* copy LLADDR information */
3994 0 : l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]);
3995 : }
3996 0 : if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) {
3997 0 : union sockunion link_layer_ipv4;
3998 :
3999 0 : if (l2_len) {
4000 0 : sockunion_family(&link_layer_ipv4) = AF_INET;
4001 0 : memcpy((void *)sockunion_get_addr(&link_layer_ipv4),
4002 : RTA_DATA(tb[NDA_LLADDR]), l2_len);
4003 : } else
4004 0 : sockunion_family(&link_layer_ipv4) = AF_UNSPEC;
4005 0 : zsend_nhrp_neighbor_notify(
4006 : cmd, ifp, &ip,
4007 0 : netlink_nbr_entry_state_to_zclient(ndm->ndm_state),
4008 : &link_layer_ipv4);
4009 : }
4010 :
4011 0 : if (h->nlmsg_type == RTM_GETNEIGH)
4012 : return 0;
4013 :
4014 : /* The neighbor is present on an SVI. From this, we locate the
4015 : * underlying
4016 : * bridge because we're only interested in neighbors on a VxLAN bridge.
4017 : * The bridge is located based on the nature of the SVI:
4018 : * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN
4019 : * interface
4020 : * and is linked to the bridge
4021 : * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge
4022 : * interface
4023 : * itself
4024 : */
4025 0 : if (IS_ZEBRA_IF_VLAN(ifp)) {
4026 0 : link_if = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
4027 0 : zif->link_ifindex);
4028 0 : if (!link_if)
4029 : return 0;
4030 0 : } else if (IS_ZEBRA_IF_BRIDGE(ifp))
4031 : link_if = ifp;
4032 : else {
4033 0 : link_if = NULL;
4034 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4035 0 : zlog_debug(
4036 : " Neighbor Entry received is not on a VLAN or a BRIDGE, ignoring");
4037 : }
4038 :
4039 0 : memset(&mac, 0, sizeof(mac));
4040 0 : if (h->nlmsg_type == RTM_NEWNEIGH) {
4041 0 : if (tb[NDA_LLADDR]) {
4042 0 : if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETH_ALEN) {
4043 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4044 0 : zlog_debug(
4045 : "%s family %s IF %s(%u) vrf %s(%u) - LLADDR is not MAC, len %lu",
4046 : nl_msg_type_to_str(
4047 : h->nlmsg_type),
4048 : nl_family_to_str(
4049 : ndm->ndm_family),
4050 : ifp->name, ndm->ndm_ifindex,
4051 : ifp->vrf->name,
4052 : ifp->vrf->vrf_id,
4053 : (unsigned long)RTA_PAYLOAD(
4054 : tb[NDA_LLADDR]));
4055 0 : return 0;
4056 : }
4057 :
4058 0 : mac_present = 1;
4059 0 : memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETH_ALEN);
4060 : }
4061 :
4062 0 : is_ext = !!(ndm->ndm_flags & NTF_EXT_LEARNED);
4063 0 : is_router = !!(ndm->ndm_flags & NTF_ROUTER);
4064 :
4065 0 : if (tb[NDA_EXT_FLAGS]) {
4066 0 : ext_flags = *(uint32_t *)RTA_DATA(tb[NDA_EXT_FLAGS]);
4067 0 : if (ext_flags & NTF_E_MH_PEER_SYNC)
4068 0 : dp_static = true;
4069 : }
4070 :
4071 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4072 0 : zlog_debug(
4073 : "Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA MAC %s state 0x%x flags 0x%x ext_flags 0x%x",
4074 : nl_msg_type_to_str(h->nlmsg_type),
4075 : nl_family_to_str(ndm->ndm_family), ifp->name,
4076 : ndm->ndm_ifindex, ifp->vrf->name,
4077 : ifp->vrf->vrf_id, &ip,
4078 : mac_present
4079 : ? prefix_mac2str(&mac, buf, sizeof(buf))
4080 : : "",
4081 : ndm->ndm_state, ndm->ndm_flags, ext_flags);
4082 :
4083 : /* If the neighbor state is valid for use, process as an add or
4084 : * update
4085 : * else process as a delete. Note that the delete handling may
4086 : * result
4087 : * in re-adding the neighbor if it is a valid "remote" neighbor.
4088 : */
4089 0 : if (ndm->ndm_state & NUD_VALID) {
4090 0 : if (zebra_evpn_mh_do_adv_reachable_neigh_only())
4091 0 : local_inactive =
4092 : !(ndm->ndm_state & NUD_LOCAL_ACTIVE);
4093 : else
4094 : /* If EVPN-MH is not enabled we treat STALE
4095 : * neighbors as locally-active and advertise
4096 : * them
4097 : */
4098 : local_inactive = false;
4099 :
4100 : /* Add local neighbors to the l3 interface database */
4101 0 : if (is_ext)
4102 0 : zebra_neigh_del(ifp, &ip);
4103 : else
4104 0 : zebra_neigh_add(ifp, &ip, &mac);
4105 :
4106 0 : if (link_if)
4107 0 : zebra_vxlan_handle_kernel_neigh_update(
4108 0 : ifp, link_if, &ip, &mac, ndm->ndm_state,
4109 : is_ext, is_router, local_inactive,
4110 : dp_static);
4111 0 : return 0;
4112 : }
4113 :
4114 :
4115 0 : zebra_neigh_del(ifp, &ip);
4116 0 : if (link_if)
4117 0 : zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
4118 0 : return 0;
4119 : }
4120 :
4121 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4122 0 : zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA",
4123 : nl_msg_type_to_str(h->nlmsg_type),
4124 : nl_family_to_str(ndm->ndm_family), ifp->name,
4125 : ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id,
4126 : &ip);
4127 :
4128 : /* Process the delete - it may result in re-adding the neighbor if it is
4129 : * a valid "remote" neighbor.
4130 : */
4131 0 : zebra_neigh_del(ifp, &ip);
4132 0 : if (link_if)
4133 0 : zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip);
4134 :
4135 : return 0;
4136 : }
4137 :
4138 0 : static int netlink_neigh_table(struct nlmsghdr *h, ns_id_t ns_id, int startup)
4139 : {
4140 0 : int len;
4141 0 : struct ndmsg *ndm;
4142 :
4143 0 : if (h->nlmsg_type != RTM_NEWNEIGH)
4144 : return 0;
4145 :
4146 : /* Length validity. */
4147 0 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
4148 0 : if (len < 0)
4149 : return -1;
4150 :
4151 : /* We are interested only in AF_INET or AF_INET6 notifications. */
4152 0 : ndm = NLMSG_DATA(h);
4153 0 : if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6)
4154 : return 0;
4155 :
4156 0 : return netlink_neigh_change(h, len);
4157 : }
4158 :
4159 : /* Request for IP neighbor information from the kernel */
4160 0 : static int netlink_request_neigh(struct nlsock *netlink_cmd, int family,
4161 : int type, ifindex_t ifindex)
4162 : {
4163 0 : struct {
4164 : struct nlmsghdr n;
4165 : struct ndmsg ndm;
4166 : char buf[256];
4167 : } req;
4168 :
4169 : /* Form the request, specifying filter (rtattr) if needed. */
4170 0 : memset(&req, 0, sizeof(req));
4171 0 : req.n.nlmsg_type = type;
4172 0 : req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
4173 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
4174 0 : req.ndm.ndm_family = family;
4175 0 : if (ifindex)
4176 0 : nl_attr_put32(&req.n, sizeof(req), NDA_IFINDEX, ifindex);
4177 :
4178 0 : return netlink_request(netlink_cmd, &req);
4179 : }
4180 :
4181 : /*
4182 : * IP Neighbor table read using netlink interface. This is invoked
4183 : * at startup.
4184 : */
4185 0 : int netlink_neigh_read(struct zebra_ns *zns)
4186 : {
4187 0 : int ret;
4188 0 : struct zebra_dplane_info dp_info;
4189 :
4190 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
4191 :
4192 : /* Get IP neighbor table. */
4193 0 : ret = netlink_request_neigh(&zns->netlink_cmd, AF_UNSPEC, RTM_GETNEIGH,
4194 : 0);
4195 0 : if (ret < 0)
4196 : return ret;
4197 0 : ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
4198 : &dp_info, 0, true);
4199 :
4200 0 : return ret;
4201 : }
4202 :
4203 : /*
4204 : * IP Neighbor table read using netlink interface. This is for a specific
4205 : * VLAN device.
4206 : */
4207 0 : int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if)
4208 : {
4209 0 : int ret = 0;
4210 0 : struct zebra_dplane_info dp_info;
4211 :
4212 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
4213 :
4214 0 : ret = netlink_request_neigh(&zns->netlink_cmd, AF_UNSPEC, RTM_GETNEIGH,
4215 : vlan_if->ifindex);
4216 0 : if (ret < 0)
4217 : return ret;
4218 0 : ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
4219 : &dp_info, 0, false);
4220 :
4221 0 : return ret;
4222 : }
4223 :
4224 : /*
4225 : * Request for a specific IP in VLAN (SVI) device from IP Neighbor table,
4226 : * read using netlink interface.
4227 : */
4228 0 : static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns,
4229 : int type,
4230 : const struct ipaddr *ip,
4231 : ifindex_t ifindex)
4232 : {
4233 0 : struct {
4234 : struct nlmsghdr n;
4235 : struct ndmsg ndm;
4236 : char buf[256];
4237 : } req;
4238 0 : int ipa_len;
4239 :
4240 : /* Form the request, specifying filter (rtattr) if needed. */
4241 0 : memset(&req, 0, sizeof(req));
4242 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
4243 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
4244 0 : req.n.nlmsg_type = type; /* RTM_GETNEIGH */
4245 0 : req.ndm.ndm_ifindex = ifindex;
4246 :
4247 0 : if (IS_IPADDR_V4(ip)) {
4248 0 : ipa_len = IPV4_MAX_BYTELEN;
4249 0 : req.ndm.ndm_family = AF_INET;
4250 :
4251 : } else {
4252 0 : ipa_len = IPV6_MAX_BYTELEN;
4253 0 : req.ndm.ndm_family = AF_INET6;
4254 : }
4255 :
4256 0 : nl_attr_put(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len);
4257 :
4258 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4259 0 : zlog_debug("%s: Tx %s family %s IF %u IP %pIA flags 0x%x",
4260 : __func__, nl_msg_type_to_str(type),
4261 : nl_family_to_str(req.ndm.ndm_family), ifindex, ip,
4262 : req.n.nlmsg_flags);
4263 :
4264 0 : return netlink_request(&zns->netlink_cmd, &req);
4265 : }
4266 :
4267 0 : int netlink_neigh_read_specific_ip(const struct ipaddr *ip,
4268 : struct interface *vlan_if)
4269 : {
4270 0 : int ret = 0;
4271 0 : struct zebra_ns *zns;
4272 0 : struct zebra_vrf *zvrf = vlan_if->vrf->info;
4273 0 : struct zebra_dplane_info dp_info;
4274 :
4275 0 : zns = zvrf->zns;
4276 :
4277 0 : zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
4278 :
4279 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4280 0 : zlog_debug("%s: neigh request IF %s(%u) IP %pIA vrf %s(%u)",
4281 : __func__, vlan_if->name, vlan_if->ifindex, ip,
4282 : vlan_if->vrf->name, vlan_if->vrf->vrf_id);
4283 :
4284 0 : ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip,
4285 : vlan_if->ifindex);
4286 0 : if (ret < 0)
4287 : return ret;
4288 :
4289 0 : ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd,
4290 : &dp_info, 1, false);
4291 :
4292 0 : return ret;
4293 : }
4294 :
4295 3 : int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id)
4296 : {
4297 3 : int len;
4298 3 : struct ndmsg *ndm;
4299 :
4300 3 : if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH
4301 : || h->nlmsg_type == RTM_GETNEIGH))
4302 : return 0;
4303 :
4304 : /* Length validity. */
4305 3 : len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg));
4306 3 : if (len < 0) {
4307 0 : zlog_err(
4308 : "%s: Message received from netlink is of a broken size %d %zu",
4309 : __func__, h->nlmsg_len,
4310 : (size_t)NLMSG_LENGTH(sizeof(struct ndmsg)));
4311 0 : return -1;
4312 : }
4313 :
4314 : /* Is this a notification for the MAC FDB or IP neighbor table? */
4315 3 : ndm = NLMSG_DATA(h);
4316 3 : if (ndm->ndm_family == AF_BRIDGE)
4317 0 : return netlink_macfdb_change(h, len, ns_id);
4318 :
4319 3 : if (ndm->ndm_type != RTN_UNICAST)
4320 : return 0;
4321 :
4322 0 : if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6)
4323 0 : return netlink_ipneigh_change(h, len, ns_id);
4324 : else {
4325 0 : flog_warn(
4326 : EC_ZEBRA_UNKNOWN_FAMILY,
4327 : "Invalid address family: %u received from kernel neighbor change: %s",
4328 : ndm->ndm_family, nl_msg_type_to_str(h->nlmsg_type));
4329 0 : return 0;
4330 : }
4331 :
4332 : return 0;
4333 : }
4334 :
4335 : /*
4336 : * Utility neighbor-update function, using info from dplane context.
4337 : */
4338 0 : static ssize_t netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx,
4339 : int cmd, void *buf, size_t buflen)
4340 : {
4341 0 : const struct ipaddr *ip;
4342 0 : const struct ethaddr *mac = NULL;
4343 0 : const struct ipaddr *link_ip = NULL;
4344 0 : const void *link_ptr = NULL;
4345 0 : char buf2[ETHER_ADDR_STRLEN];
4346 :
4347 0 : int llalen;
4348 0 : uint8_t flags;
4349 0 : uint16_t state;
4350 0 : uint8_t family;
4351 0 : uint32_t update_flags;
4352 0 : uint32_t ext_flags = 0;
4353 0 : bool ext = false;
4354 0 : int proto = RTPROT_ZEBRA;
4355 :
4356 0 : if (dplane_ctx_get_type(ctx) != 0)
4357 0 : proto = zebra2proto(dplane_ctx_get_type(ctx));
4358 :
4359 0 : ip = dplane_ctx_neigh_get_ipaddr(ctx);
4360 :
4361 0 : if (dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_INSTALL
4362 0 : || dplane_ctx_get_op(ctx) == DPLANE_OP_NEIGH_IP_DELETE) {
4363 0 : link_ip = dplane_ctx_neigh_get_link_ip(ctx);
4364 0 : llalen = IPADDRSZ(link_ip);
4365 0 : link_ptr = (const void *)&(link_ip->ip.addr);
4366 0 : ipaddr2str(link_ip, buf2, sizeof(buf2));
4367 : } else {
4368 0 : mac = dplane_ctx_neigh_get_mac(ctx);
4369 0 : llalen = ETH_ALEN;
4370 0 : link_ptr = (const void *)mac;
4371 0 : if (is_zero_mac(mac))
4372 : mac = NULL;
4373 0 : if (mac)
4374 0 : prefix_mac2str(mac, buf2, sizeof(buf2));
4375 : else
4376 0 : snprintf(buf2, sizeof(buf2), "null");
4377 : }
4378 0 : update_flags = dplane_ctx_neigh_get_update_flags(ctx);
4379 0 : flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx));
4380 0 : state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx));
4381 :
4382 0 : family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6;
4383 :
4384 0 : if (update_flags & DPLANE_NEIGH_REMOTE) {
4385 0 : flags |= NTF_EXT_LEARNED;
4386 : /* if it was static-local previously we need to clear the
4387 : * ext flags on replace with remote
4388 : */
4389 0 : if (update_flags & DPLANE_NEIGH_WAS_STATIC)
4390 0 : ext = true;
4391 0 : } else if (!(update_flags & DPLANE_NEIGH_NO_EXTENSION)) {
4392 0 : ext = true;
4393 : /* local neigh */
4394 0 : if (update_flags & DPLANE_NEIGH_SET_STATIC)
4395 0 : ext_flags |= NTF_E_MH_PEER_SYNC;
4396 : }
4397 0 : if (IS_ZEBRA_DEBUG_KERNEL)
4398 0 : zlog_debug(
4399 : "Tx %s family %s IF %s(%u) Neigh %pIA %s %s flags 0x%x state 0x%x %sext_flags 0x%x",
4400 : nl_msg_type_to_str(cmd), nl_family_to_str(family),
4401 : dplane_ctx_get_ifname(ctx), dplane_ctx_get_ifindex(ctx),
4402 : ip, link_ip ? "Link" : "MAC", buf2, flags, state,
4403 : ext ? "ext " : "", ext_flags);
4404 :
4405 0 : return netlink_neigh_update_msg_encode(
4406 : ctx, cmd, link_ptr, llalen, ip, true, family, RTN_UNICAST,
4407 : flags, state, 0 /*nhg*/, false /*nfy*/, 0 /*nfy_flags*/, ext,
4408 : ext_flags, buf, buflen, proto);
4409 : }
4410 :
4411 0 : static int netlink_neigh_table_update_ctx(const struct zebra_dplane_ctx *ctx,
4412 : void *data, size_t datalen)
4413 : {
4414 0 : struct {
4415 : struct nlmsghdr n;
4416 : struct ndtmsg ndtm;
4417 : char buf[];
4418 0 : } *req = data;
4419 0 : struct rtattr *nest;
4420 0 : uint8_t family;
4421 0 : ifindex_t idx;
4422 0 : uint32_t val;
4423 :
4424 0 : if (datalen < sizeof(*req))
4425 : return 0;
4426 0 : memset(req, 0, sizeof(*req));
4427 0 : family = dplane_ctx_neightable_get_family(ctx);
4428 0 : idx = dplane_ctx_get_ifindex(ctx);
4429 :
4430 0 : req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndtmsg));
4431 0 : req->n.nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE;
4432 0 : req->n.nlmsg_type = RTM_SETNEIGHTBL;
4433 0 : req->ndtm.ndtm_family = family;
4434 :
4435 0 : nl_attr_put(&req->n, datalen, NDTA_NAME,
4436 : family == AF_INET ? "arp_cache" : "ndisc_cache", 10);
4437 0 : nest = nl_attr_nest(&req->n, datalen, NDTA_PARMS);
4438 0 : if (nest == NULL)
4439 : return 0;
4440 0 : if (!nl_attr_put(&req->n, datalen, NDTPA_IFINDEX, &idx, sizeof(idx)))
4441 : return 0;
4442 0 : val = dplane_ctx_neightable_get_app_probes(ctx);
4443 0 : if (!nl_attr_put(&req->n, datalen, NDTPA_APP_PROBES, &val, sizeof(val)))
4444 : return 0;
4445 0 : val = dplane_ctx_neightable_get_mcast_probes(ctx);
4446 0 : if (!nl_attr_put(&req->n, datalen, NDTPA_MCAST_PROBES, &val,
4447 : sizeof(val)))
4448 : return 0;
4449 0 : val = dplane_ctx_neightable_get_ucast_probes(ctx);
4450 0 : if (!nl_attr_put(&req->n, datalen, NDTPA_UCAST_PROBES, &val,
4451 : sizeof(val)))
4452 : return 0;
4453 0 : nl_attr_nest_end(&req->n, nest);
4454 :
4455 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
4456 : }
4457 :
4458 0 : static ssize_t netlink_neigh_msg_encoder(struct zebra_dplane_ctx *ctx,
4459 : void *buf, size_t buflen)
4460 : {
4461 0 : ssize_t ret = 0;
4462 :
4463 0 : switch (dplane_ctx_get_op(ctx)) {
4464 0 : case DPLANE_OP_NEIGH_INSTALL:
4465 : case DPLANE_OP_NEIGH_UPDATE:
4466 : case DPLANE_OP_NEIGH_DISCOVER:
4467 : case DPLANE_OP_NEIGH_IP_INSTALL:
4468 0 : ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH, buf, buflen);
4469 0 : break;
4470 0 : case DPLANE_OP_NEIGH_DELETE:
4471 : case DPLANE_OP_NEIGH_IP_DELETE:
4472 0 : ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH, buf, buflen);
4473 0 : break;
4474 0 : case DPLANE_OP_VTEP_ADD:
4475 0 : ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH, buf,
4476 : buflen);
4477 0 : break;
4478 0 : case DPLANE_OP_VTEP_DELETE:
4479 0 : ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH, buf,
4480 : buflen);
4481 0 : break;
4482 0 : case DPLANE_OP_NEIGH_TABLE_UPDATE:
4483 0 : ret = netlink_neigh_table_update_ctx(ctx, buf, buflen);
4484 0 : break;
4485 0 : case DPLANE_OP_ROUTE_INSTALL:
4486 : case DPLANE_OP_ROUTE_UPDATE:
4487 : case DPLANE_OP_ROUTE_DELETE:
4488 : case DPLANE_OP_ROUTE_NOTIFY:
4489 : case DPLANE_OP_NH_INSTALL:
4490 : case DPLANE_OP_NH_UPDATE:
4491 : case DPLANE_OP_NH_DELETE:
4492 : case DPLANE_OP_LSP_INSTALL:
4493 : case DPLANE_OP_LSP_UPDATE:
4494 : case DPLANE_OP_LSP_DELETE:
4495 : case DPLANE_OP_LSP_NOTIFY:
4496 : case DPLANE_OP_PW_INSTALL:
4497 : case DPLANE_OP_PW_UNINSTALL:
4498 : case DPLANE_OP_SYS_ROUTE_ADD:
4499 : case DPLANE_OP_SYS_ROUTE_DELETE:
4500 : case DPLANE_OP_ADDR_INSTALL:
4501 : case DPLANE_OP_ADDR_UNINSTALL:
4502 : case DPLANE_OP_MAC_INSTALL:
4503 : case DPLANE_OP_MAC_DELETE:
4504 : case DPLANE_OP_RULE_ADD:
4505 : case DPLANE_OP_RULE_DELETE:
4506 : case DPLANE_OP_RULE_UPDATE:
4507 : case DPLANE_OP_BR_PORT_UPDATE:
4508 : case DPLANE_OP_IPTABLE_ADD:
4509 : case DPLANE_OP_IPTABLE_DELETE:
4510 : case DPLANE_OP_IPSET_ADD:
4511 : case DPLANE_OP_IPSET_DELETE:
4512 : case DPLANE_OP_IPSET_ENTRY_ADD:
4513 : case DPLANE_OP_IPSET_ENTRY_DELETE:
4514 : case DPLANE_OP_GRE_SET:
4515 : case DPLANE_OP_INTF_ADDR_ADD:
4516 : case DPLANE_OP_INTF_ADDR_DEL:
4517 : case DPLANE_OP_INTF_NETCONFIG:
4518 : case DPLANE_OP_INTF_INSTALL:
4519 : case DPLANE_OP_INTF_UPDATE:
4520 : case DPLANE_OP_INTF_DELETE:
4521 : case DPLANE_OP_TC_QDISC_INSTALL:
4522 : case DPLANE_OP_TC_QDISC_UNINSTALL:
4523 : case DPLANE_OP_TC_CLASS_ADD:
4524 : case DPLANE_OP_TC_CLASS_DELETE:
4525 : case DPLANE_OP_TC_CLASS_UPDATE:
4526 : case DPLANE_OP_TC_FILTER_ADD:
4527 : case DPLANE_OP_TC_FILTER_DELETE:
4528 : case DPLANE_OP_TC_FILTER_UPDATE:
4529 : case DPLANE_OP_NONE:
4530 0 : ret = -1;
4531 : }
4532 :
4533 0 : return ret;
4534 : }
4535 :
4536 : /*
4537 : * Update MAC, using dataplane context object.
4538 : */
4539 :
4540 0 : enum netlink_msg_status netlink_put_mac_update_msg(struct nl_batch *bth,
4541 : struct zebra_dplane_ctx *ctx)
4542 : {
4543 0 : return netlink_batch_add_msg(bth, ctx, netlink_macfdb_update_ctx,
4544 : false);
4545 : }
4546 :
4547 : enum netlink_msg_status
4548 0 : netlink_put_neigh_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx)
4549 : {
4550 0 : return netlink_batch_add_msg(bth, ctx, netlink_neigh_msg_encoder,
4551 : false);
4552 : }
4553 :
4554 : /*
4555 : * MPLS label forwarding table change via netlink interface, using dataplane
4556 : * context information.
4557 : */
4558 0 : ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx,
4559 : void *buf, size_t buflen)
4560 : {
4561 0 : mpls_lse_t lse;
4562 0 : const struct nhlfe_list_head *head;
4563 0 : const struct zebra_nhlfe *nhlfe;
4564 0 : struct nexthop *nexthop = NULL;
4565 0 : unsigned int nexthop_num;
4566 0 : const char *routedesc;
4567 0 : int route_type;
4568 0 : struct prefix p = {0};
4569 0 : struct nlsock *nl =
4570 0 : kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx));
4571 :
4572 0 : struct {
4573 : struct nlmsghdr n;
4574 : struct rtmsg r;
4575 : char buf[0];
4576 0 : } *req = buf;
4577 :
4578 0 : if (buflen < sizeof(*req))
4579 : return 0;
4580 :
4581 0 : memset(req, 0, sizeof(*req));
4582 :
4583 : /*
4584 : * Count # nexthops so we can decide whether to use singlepath
4585 : * or multipath case.
4586 : */
4587 0 : nexthop_num = 0;
4588 0 : head = dplane_ctx_get_nhlfe_list(ctx);
4589 0 : frr_each(nhlfe_list_const, head, nhlfe) {
4590 0 : nexthop = nhlfe->nexthop;
4591 0 : if (!nexthop)
4592 0 : continue;
4593 0 : if (cmd == RTM_NEWROUTE) {
4594 : /* Count all selected NHLFEs */
4595 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
4596 0 : && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
4597 0 : nexthop_num++;
4598 : } else { /* DEL */
4599 : /* Count all installed NHLFEs */
4600 0 : if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED)
4601 0 : && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
4602 0 : nexthop_num++;
4603 : }
4604 : }
4605 :
4606 0 : if ((nexthop_num == 0) ||
4607 0 : (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE)))
4608 0 : return 0;
4609 :
4610 0 : req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
4611 0 : req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
4612 0 : req->n.nlmsg_type = cmd;
4613 0 : req->n.nlmsg_pid = nl->snl.nl_pid;
4614 :
4615 0 : req->r.rtm_family = AF_MPLS;
4616 0 : req->r.rtm_table = RT_TABLE_MAIN;
4617 0 : req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
4618 0 : req->r.rtm_scope = RT_SCOPE_UNIVERSE;
4619 0 : req->r.rtm_type = RTN_UNICAST;
4620 :
4621 0 : if (cmd == RTM_NEWROUTE) {
4622 : /* We do a replace to handle update. */
4623 0 : req->n.nlmsg_flags |= NLM_F_REPLACE;
4624 :
4625 : /* set the protocol value if installing */
4626 0 : route_type = re_type_from_lsp_type(
4627 0 : dplane_ctx_get_best_nhlfe(ctx)->type);
4628 0 : req->r.rtm_protocol = zebra2proto(route_type);
4629 : }
4630 :
4631 : /* Fill destination */
4632 0 : lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1);
4633 0 : if (!nl_attr_put(&req->n, buflen, RTA_DST, &lse, sizeof(mpls_lse_t)))
4634 : return 0;
4635 :
4636 : /* Fill nexthops (paths) based on single-path or multipath. The paths
4637 : * chosen depend on the operation.
4638 : */
4639 0 : if (nexthop_num == 1) {
4640 0 : routedesc = "single-path";
4641 0 : _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
4642 : routedesc);
4643 :
4644 0 : nexthop_num = 0;
4645 0 : frr_each(nhlfe_list_const, head, nhlfe) {
4646 0 : nexthop = nhlfe->nexthop;
4647 0 : if (!nexthop)
4648 0 : continue;
4649 :
4650 0 : if ((cmd == RTM_NEWROUTE
4651 0 : && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
4652 0 : && CHECK_FLAG(nexthop->flags,
4653 : NEXTHOP_FLAG_ACTIVE)))
4654 0 : || (cmd == RTM_DELROUTE
4655 0 : && (CHECK_FLAG(nhlfe->flags,
4656 : NHLFE_FLAG_INSTALLED)
4657 0 : && CHECK_FLAG(nexthop->flags,
4658 : NEXTHOP_FLAG_FIB)))) {
4659 : /* Add the gateway */
4660 0 : if (!_netlink_mpls_build_singlepath(
4661 : &p, routedesc, nhlfe, &req->n,
4662 : &req->r, buflen, cmd))
4663 : return false;
4664 :
4665 0 : nexthop_num++;
4666 : break;
4667 : }
4668 : }
4669 : } else { /* Multipath case */
4670 0 : struct rtattr *nest;
4671 0 : const union g_addr *src1 = NULL;
4672 :
4673 0 : nest = nl_attr_nest(&req->n, buflen, RTA_MULTIPATH);
4674 0 : if (!nest)
4675 0 : return 0;
4676 :
4677 0 : routedesc = "multipath";
4678 0 : _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx),
4679 : routedesc);
4680 :
4681 0 : nexthop_num = 0;
4682 0 : frr_each(nhlfe_list_const, head, nhlfe) {
4683 0 : nexthop = nhlfe->nexthop;
4684 0 : if (!nexthop)
4685 0 : continue;
4686 :
4687 0 : if ((cmd == RTM_NEWROUTE
4688 0 : && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
4689 0 : && CHECK_FLAG(nexthop->flags,
4690 : NEXTHOP_FLAG_ACTIVE)))
4691 0 : || (cmd == RTM_DELROUTE
4692 0 : && (CHECK_FLAG(nhlfe->flags,
4693 : NHLFE_FLAG_INSTALLED)
4694 0 : && CHECK_FLAG(nexthop->flags,
4695 : NEXTHOP_FLAG_FIB)))) {
4696 0 : nexthop_num++;
4697 :
4698 : /* Build the multipath */
4699 0 : if (!_netlink_mpls_build_multipath(
4700 : &p, routedesc, nhlfe, &req->n,
4701 : buflen, &req->r, &src1))
4702 : return 0;
4703 : }
4704 : }
4705 :
4706 : /* Add the multipath */
4707 0 : nl_attr_nest_end(&req->n, nest);
4708 : }
4709 :
4710 0 : return NLMSG_ALIGN(req->n.nlmsg_len);
4711 : }
4712 :
4713 : /****************************************************************************
4714 : * This code was developed in a branch that didn't have dplane APIs for
4715 : * MAC updates. Hence the use of the legacy style. It will be moved to
4716 : * the new dplane style pre-merge to master. XXX
4717 : */
4718 0 : static int netlink_fdb_nh_update(uint32_t nh_id, struct in_addr vtep_ip)
4719 : {
4720 0 : struct {
4721 : struct nlmsghdr n;
4722 : struct nhmsg nhm;
4723 : char buf[256];
4724 : } req;
4725 0 : int cmd = RTM_NEWNEXTHOP;
4726 0 : struct zebra_vrf *zvrf;
4727 0 : struct zebra_ns *zns;
4728 :
4729 0 : zvrf = zebra_vrf_get_evpn();
4730 0 : zns = zvrf->zns;
4731 :
4732 0 : memset(&req, 0, sizeof(req));
4733 :
4734 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
4735 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
4736 0 : req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
4737 0 : req.n.nlmsg_type = cmd;
4738 0 : req.nhm.nh_family = AF_INET;
4739 :
4740 0 : if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
4741 : return -1;
4742 0 : if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
4743 : return -1;
4744 0 : if (!nl_attr_put(&req.n, sizeof(req), NHA_GATEWAY,
4745 : &vtep_ip, IPV4_MAX_BYTELEN))
4746 : return -1;
4747 :
4748 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
4749 0 : zlog_debug("Tx %s fdb-nh 0x%x %pI4",
4750 : nl_msg_type_to_str(cmd), nh_id, &vtep_ip);
4751 : }
4752 :
4753 0 : return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
4754 : false);
4755 : }
4756 :
4757 0 : static int netlink_fdb_nh_del(uint32_t nh_id)
4758 : {
4759 0 : struct {
4760 : struct nlmsghdr n;
4761 : struct nhmsg nhm;
4762 : char buf[256];
4763 : } req;
4764 0 : int cmd = RTM_DELNEXTHOP;
4765 0 : struct zebra_vrf *zvrf;
4766 0 : struct zebra_ns *zns;
4767 :
4768 0 : zvrf = zebra_vrf_get_evpn();
4769 0 : zns = zvrf->zns;
4770 :
4771 0 : memset(&req, 0, sizeof(req));
4772 :
4773 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
4774 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
4775 0 : req.n.nlmsg_type = cmd;
4776 0 : req.nhm.nh_family = AF_UNSPEC;
4777 :
4778 0 : if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nh_id))
4779 : return -1;
4780 :
4781 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
4782 0 : zlog_debug("Tx %s fdb-nh 0x%x",
4783 : nl_msg_type_to_str(cmd), nh_id);
4784 : }
4785 :
4786 0 : return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
4787 : false);
4788 : }
4789 :
4790 0 : static int netlink_fdb_nhg_update(uint32_t nhg_id, uint32_t nh_cnt,
4791 : struct nh_grp *nh_ids)
4792 0 : {
4793 0 : struct {
4794 : struct nlmsghdr n;
4795 : struct nhmsg nhm;
4796 : char buf[256];
4797 : } req;
4798 0 : int cmd = RTM_NEWNEXTHOP;
4799 0 : struct zebra_vrf *zvrf;
4800 0 : struct zebra_ns *zns;
4801 0 : struct nexthop_grp grp[nh_cnt];
4802 0 : uint32_t i;
4803 :
4804 0 : zvrf = zebra_vrf_get_evpn();
4805 0 : zns = zvrf->zns;
4806 :
4807 0 : memset(&req, 0, sizeof(req));
4808 :
4809 0 : req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
4810 0 : req.n.nlmsg_flags = NLM_F_REQUEST;
4811 0 : req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
4812 0 : req.n.nlmsg_type = cmd;
4813 0 : req.nhm.nh_family = AF_UNSPEC;
4814 :
4815 0 : if (!nl_attr_put32(&req.n, sizeof(req), NHA_ID, nhg_id))
4816 : return -1;
4817 0 : if (!nl_attr_put(&req.n, sizeof(req), NHA_FDB, NULL, 0))
4818 : return -1;
4819 0 : memset(&grp, 0, sizeof(grp));
4820 0 : for (i = 0; i < nh_cnt; ++i) {
4821 0 : grp[i].id = nh_ids[i].id;
4822 0 : grp[i].weight = nh_ids[i].weight;
4823 : }
4824 0 : if (!nl_attr_put(&req.n, sizeof(req), NHA_GROUP,
4825 : grp, nh_cnt * sizeof(struct nexthop_grp)))
4826 : return -1;
4827 :
4828 :
4829 0 : if (IS_ZEBRA_DEBUG_KERNEL || IS_ZEBRA_DEBUG_EVPN_MH_NH) {
4830 0 : char vtep_str[ES_VTEP_LIST_STR_SZ];
4831 0 : char nh_buf[16];
4832 :
4833 0 : vtep_str[0] = '\0';
4834 0 : for (i = 0; i < nh_cnt; ++i) {
4835 0 : snprintf(nh_buf, sizeof(nh_buf), "%u ",
4836 : grp[i].id);
4837 0 : strlcat(vtep_str, nh_buf, sizeof(vtep_str));
4838 : }
4839 :
4840 0 : zlog_debug("Tx %s fdb-nhg 0x%x %s",
4841 : nl_msg_type_to_str(cmd), nhg_id, vtep_str);
4842 : }
4843 :
4844 0 : return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns,
4845 : false);
4846 : }
4847 :
4848 0 : static int netlink_fdb_nhg_del(uint32_t nhg_id)
4849 : {
4850 0 : return netlink_fdb_nh_del(nhg_id);
4851 : }
4852 :
4853 0 : int kernel_upd_mac_nh(uint32_t nh_id, struct in_addr vtep_ip)
4854 : {
4855 0 : return netlink_fdb_nh_update(nh_id, vtep_ip);
4856 : }
4857 :
4858 0 : int kernel_del_mac_nh(uint32_t nh_id)
4859 : {
4860 0 : return netlink_fdb_nh_del(nh_id);
4861 : }
4862 :
4863 0 : int kernel_upd_mac_nhg(uint32_t nhg_id, uint32_t nh_cnt,
4864 : struct nh_grp *nh_ids)
4865 : {
4866 0 : return netlink_fdb_nhg_update(nhg_id, nh_cnt, nh_ids);
4867 : }
4868 :
4869 0 : int kernel_del_mac_nhg(uint32_t nhg_id)
4870 : {
4871 0 : return netlink_fdb_nhg_del(nhg_id);
4872 : }
4873 :
4874 : #endif /* HAVE_NETLINK */
|