]> git.proxmox.com Git - mirror_frr.git/blame - zebra/zebra_fpm_netlink.c
Merge pull request #9345 from mjstapp/fix_lib_zmq_free
[mirror_frr.git] / zebra / zebra_fpm_netlink.c
CommitLineData
5adc2528
AS
1/*
2 * Code for encoding/decoding FPM messages that are in netlink format.
3 *
4 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
5 * Copyright (C) 2012 by Open Source Routing.
6 * Copyright (C) 2012 by Internet Systems Consortium, Inc. ("ISC")
7 *
8 * This file is part of GNU Zebra.
9 *
10 * GNU Zebra is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * GNU Zebra is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
896014f4
DL
20 * You should have received a copy of the GNU General Public License along
21 * with this program; see the file COPYING; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
5adc2528
AS
23 */
24
25#include <zebra.h>
26
ddfeb486
DL
27#ifdef HAVE_NETLINK
28
5adc2528
AS
29#include "log.h"
30#include "rib.h"
82f97584 31#include "vty.h"
e3be0432 32#include "prefix.h"
5adc2528 33
1fdc9eae 34#include "zebra/zserv.h"
b3f2b590 35#include "zebra/zebra_router.h"
85a75f1e 36#include "zebra/zebra_dplane.h"
1fdc9eae 37#include "zebra/zebra_ns.h"
38#include "zebra/zebra_vrf.h"
39#include "zebra/kernel_netlink.h"
40#include "zebra/rt_netlink.h"
fb018d25 41#include "nexthop.h"
5adc2528 42
1fdc9eae 43#include "zebra/zebra_fpm_private.h"
9d21b7c6 44#include "zebra/zebra_vxlan_private.h"
1b09e77e 45#include "zebra/interface.h"
5adc2528 46
5adc2528
AS
47/*
48 * af_addr_size
49 *
50 * The size of an address in a given address family.
51 */
d7c0a89a 52static size_t af_addr_size(uint8_t af)
5adc2528 53{
d62a17ae 54 switch (af) {
55
56 case AF_INET:
57 return 4;
d62a17ae 58 case AF_INET6:
59 return 16;
d62a17ae 60 default:
61 assert(0);
62 return 16;
63 }
5adc2528
AS
64}
65
9d21b7c6
AD
66/*
67 * We plan to use RTA_ENCAP_TYPE attribute for VxLAN encap as well.
68 * Currently, values 0 to 8 for this attribute are used by lwtunnel_encap_types
69 * So, we cannot use these values for VxLAN encap.
70 */
71enum fpm_nh_encap_type_t {
72 FPM_NH_ENCAP_NONE = 0,
73 FPM_NH_ENCAP_VXLAN = 100,
74 FPM_NH_ENCAP_MAX,
75};
76
77/*
78 * fpm_nh_encap_type_to_str
79 */
80static const char *fpm_nh_encap_type_to_str(enum fpm_nh_encap_type_t encap_type)
81{
82 switch (encap_type) {
83 case FPM_NH_ENCAP_NONE:
84 return "none";
85
86 case FPM_NH_ENCAP_VXLAN:
87 return "VxLAN";
88
89 case FPM_NH_ENCAP_MAX:
90 return "invalid";
91 }
92
93 return "invalid";
94}
95
96struct vxlan_encap_info_t {
97 vni_t vni;
98};
99
100enum vxlan_encap_info_type_t {
101 VXLAN_VNI = 0,
102};
103
104struct fpm_nh_encap_info_t {
105 enum fpm_nh_encap_type_t encap_type;
106 union {
107 struct vxlan_encap_info_t vxlan_encap;
108 };
109};
110
5adc2528 111/*
7cf19069 112 * netlink_nh_info
5adc2528
AS
113 *
114 * Holds information about a single nexthop for netlink. These info
115 * structures are transient and may contain pointers into rib
116 * data structures for convenience.
117 */
7cf19069 118struct netlink_nh_info {
d62a17ae 119 uint32_t if_index;
120 union g_addr *gateway;
121
122 /*
123 * Information from the struct nexthop from which this nh was
124 * derived. For debug purposes only.
125 */
126 int recursive;
127 enum nexthop_types_t type;
9d21b7c6 128 struct fpm_nh_encap_info_t encap_info;
7cf19069 129};
5adc2528
AS
130
131/*
67ceb408 132 * netlink_route_info
5adc2528
AS
133 *
134 * A structure for holding information for a netlink route message.
135 */
67ceb408 136struct netlink_route_info {
869a5f71 137 uint32_t nlmsg_pid;
d62a17ae 138 uint16_t nlmsg_type;
d7c0a89a 139 uint8_t rtm_type;
d62a17ae 140 uint32_t rtm_table;
d7c0a89a
QY
141 uint8_t rtm_protocol;
142 uint8_t af;
d62a17ae 143 struct prefix *prefix;
144 uint32_t *metric;
145 unsigned int num_nhs;
146
147 /*
148 * Nexthop structures
149 */
7cf19069 150 struct netlink_nh_info nhs[MULTIPATH_NUM];
d62a17ae 151 union g_addr *pref_src;
67ceb408 152};
5adc2528
AS
153
154/*
155 * netlink_route_info_add_nh
156 *
157 * Add information about the given nexthop to the given route info
158 * structure.
159 *
2951a7a4 160 * Returns true if a nexthop was added, false otherwise.
5adc2528 161 */
67ceb408 162static int netlink_route_info_add_nh(struct netlink_route_info *ri,
9d21b7c6
AD
163 struct nexthop *nexthop,
164 struct route_entry *re)
5adc2528 165{
7cf19069 166 struct netlink_nh_info nhi;
d62a17ae 167 union g_addr *src;
1b09e77e
AD
168 struct zebra_vrf *zvrf = NULL;
169 struct interface *ifp = NULL, *link_if = NULL;
170 struct zebra_if *zif = NULL;
171 vni_t vni = 0;
d62a17ae 172
173 memset(&nhi, 0, sizeof(nhi));
174 src = NULL;
175
7e3a1ec7 176 if (ri->num_nhs >= (int)array_size(ri->nhs))
d62a17ae 177 return 0;
178
179 nhi.recursive = nexthop->rparent ? 1 : 0;
180 nhi.type = nexthop->type;
181 nhi.if_index = nexthop->ifindex;
182
183 if (nexthop->type == NEXTHOP_TYPE_IPV4
184 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
185 nhi.gateway = &nexthop->gate;
975a328e 186 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
d62a17ae 187 src = &nexthop->src;
188 }
189
190 if (nexthop->type == NEXTHOP_TYPE_IPV6
191 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) {
316d2d52
NK
192 /* Special handling for IPv4 route with IPv6 Link Local next hop
193 */
194 if (ri->af == AF_INET)
195 nhi.gateway = &ipv4ll_gateway;
196 else
197 nhi.gateway = &nexthop->gate;
d62a17ae 198 }
199
200 if (nexthop->type == NEXTHOP_TYPE_IFINDEX) {
975a328e 201 if (nexthop->src.ipv4.s_addr != INADDR_ANY)
d62a17ae 202 src = &nexthop->src;
203 }
204
205 if (!nhi.gateway && nhi.if_index == 0)
206 return 0;
207
9d21b7c6
AD
208 if (re && CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
209 nhi.encap_info.encap_type = FPM_NH_ENCAP_VXLAN;
210
1b09e77e
AD
211 /* Extract VNI id for the nexthop SVI interface */
212 zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
213 if (zvrf) {
214 ifp = if_lookup_by_index_per_ns(zvrf->zns,
215 nexthop->ifindex);
216 if (ifp) {
217 zif = (struct zebra_if *)ifp->info;
218 if (zif) {
219 if (IS_ZEBRA_IF_BRIDGE(ifp))
220 link_if = ifp;
221 else if (IS_ZEBRA_IF_VLAN(ifp))
222 link_if =
223 if_lookup_by_index_per_ns(
224 zvrf->zns,
225 zif->link_ifindex);
226 if (link_if)
227 vni = vni_id_from_svi(ifp,
228 link_if);
229 }
230 }
9d21b7c6 231 }
1b09e77e
AD
232
233 nhi.encap_info.vxlan_encap.vni = vni;
9d21b7c6
AD
234 }
235
d62a17ae 236 /*
237 * We have a valid nhi. Copy the structure over to the route_info.
238 */
239 ri->nhs[ri->num_nhs] = nhi;
240 ri->num_nhs++;
241
242 if (src && !ri->pref_src)
243 ri->pref_src = src;
244
245 return 1;
5adc2528
AS
246}
247
248/*
249 * netlink_proto_from_route_type
250 */
d7c0a89a 251static uint8_t netlink_proto_from_route_type(int type)
5adc2528 252{
d62a17ae 253 switch (type) {
254 case ZEBRA_ROUTE_KERNEL:
255 case ZEBRA_ROUTE_CONNECT:
256 return RTPROT_KERNEL;
257
258 default:
259 return RTPROT_ZEBRA;
260 }
5adc2528
AS
261}
262
263/*
264 * netlink_route_info_fill
265 *
266 * Fill out the route information object from the given route.
267 *
2951a7a4 268 * Returns true on success and false on failure.
5adc2528 269 */
67ceb408 270static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
d62a17ae 271 rib_dest_t *dest, struct route_entry *re)
5adc2528 272{
d62a17ae 273 struct nexthop *nexthop;
869a5f71
DE
274 struct rib_table_info *table_info =
275 rib_table_info(rib_dest_table(dest));
276 struct zebra_vrf *zvrf = table_info->zvrf;
d62a17ae 277
278 memset(ri, 0, sizeof(*ri));
279
280 ri->prefix = rib_dest_prefix(dest);
281 ri->af = rib_dest_af(dest);
282
869a5f71 283 if (zvrf && zvrf->zns)
80dcc388 284 ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid;
869a5f71 285
d62a17ae 286 ri->nlmsg_type = cmd;
869a5f71 287 ri->rtm_table = table_info->table_id;
d62a17ae 288 ri->rtm_protocol = RTPROT_UNSPEC;
289
290 /*
291 * An RTM_DELROUTE need not be accompanied by any nexthops,
292 * particularly in our communication with the FPM.
293 */
294 if (cmd == RTM_DELROUTE && !re)
295 return 1;
296
297 if (!re) {
5e81f5dd 298 zfpm_debug("%s: Expected non-NULL re pointer", __func__);
d62a17ae 299 return 0;
300 }
301
302 ri->rtm_protocol = netlink_proto_from_route_type(re->type);
a8309422 303 ri->rtm_type = RTN_UNICAST;
d62a17ae 304 ri->metric = &re->metric;
305
c415d895 306 for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
b3f2b590 307 if (ri->num_nhs >= zrouter.multipath_num)
d62a17ae 308 break;
309
310 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
311 continue;
312
a8309422
DL
313 if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) {
314 switch (nexthop->bh_type) {
315 case BLACKHOLE_ADMINPROHIB:
316 ri->rtm_type = RTN_PROHIBIT;
317 break;
318 case BLACKHOLE_REJECT:
319 ri->rtm_type = RTN_UNREACHABLE;
320 break;
321 case BLACKHOLE_NULL:
322 default:
323 ri->rtm_type = RTN_BLACKHOLE;
324 break;
325 }
a8309422
DL
326 }
327
d62a17ae 328 if ((cmd == RTM_NEWROUTE
329 && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
330 || (cmd == RTM_DELROUTE
677c1dd5 331 && CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))) {
9d21b7c6 332 netlink_route_info_add_nh(ri, nexthop, re);
d62a17ae 333 }
334 }
335
94f77863
DE
336 if (ri->num_nhs == 0) {
337 switch (ri->rtm_type) {
338 case RTN_PROHIBIT:
339 case RTN_UNREACHABLE:
340 case RTN_BLACKHOLE:
341 break;
342 default:
343 /* If there is no useful nexthop then return. */
344 zfpm_debug(
345 "netlink_encode_route(): No useful nexthop.");
346 return 0;
347 }
d62a17ae 348 }
349
350 return 1;
5adc2528
AS
351}
352
353/*
354 * netlink_route_info_encode
355 *
356 * Returns the number of bytes written to the buffer. 0 or a negative
357 * value indicates an error.
358 */
67ceb408
DS
359static int netlink_route_info_encode(struct netlink_route_info *ri,
360 char *in_buf, size_t in_buf_len)
5adc2528 361{
d62a17ae 362 size_t bytelen;
363 unsigned int nexthop_num = 0;
364 size_t buf_offset;
7cf19069 365 struct netlink_nh_info *nhi;
9d21b7c6 366 enum fpm_nh_encap_type_t encap;
312a6bee
JU
367 struct rtattr *nest, *inner_nest;
368 struct rtnexthop *rtnh;
9d21b7c6 369 struct vxlan_encap_info_t *vxlan;
92d6f769 370 struct in6_addr ipv6;
5adc2528 371
d62a17ae 372 struct {
373 struct nlmsghdr n;
374 struct rtmsg r;
375 char buf[1];
376 } * req;
5adc2528 377
d62a17ae 378 req = (void *)in_buf;
5adc2528 379
d62a17ae 380 buf_offset = ((char *)req->buf) - ((char *)req);
5adc2528 381
d62a17ae 382 if (in_buf_len < buf_offset) {
383 assert(0);
384 return 0;
385 }
5adc2528 386
d62a17ae 387 memset(req, 0, buf_offset);
5adc2528 388
d62a17ae 389 bytelen = af_addr_size(ri->af);
5adc2528 390
d62a17ae 391 req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
392 req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
869a5f71 393 req->n.nlmsg_pid = ri->nlmsg_pid;
d62a17ae 394 req->n.nlmsg_type = ri->nlmsg_type;
395 req->r.rtm_family = ri->af;
6dfcd754
AD
396
397 /*
398 * rtm_table field is a uchar field which can accomodate table_id less
399 * than 256.
400 * To support table id greater than 255, if the table_id is greater than
401 * 255, set rtm_table to RT_TABLE_UNSPEC and add RTA_TABLE attribute
402 * with 32 bit value as the table_id.
403 */
404 if (ri->rtm_table < 256)
405 req->r.rtm_table = ri->rtm_table;
406 else {
407 req->r.rtm_table = RT_TABLE_UNSPEC;
312a6bee 408 nl_attr_put32(&req->n, in_buf_len, RTA_TABLE, ri->rtm_table);
6dfcd754
AD
409 }
410
d62a17ae 411 req->r.rtm_dst_len = ri->prefix->prefixlen;
412 req->r.rtm_protocol = ri->rtm_protocol;
413 req->r.rtm_scope = RT_SCOPE_UNIVERSE;
5adc2528 414
312a6bee
JU
415 nl_attr_put(&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix,
416 bytelen);
5adc2528 417
d62a17ae 418 req->r.rtm_type = ri->rtm_type;
5adc2528 419
d62a17ae 420 /* Metric. */
421 if (ri->metric)
312a6bee 422 nl_attr_put32(&req->n, in_buf_len, RTA_PRIORITY, *ri->metric);
5adc2528 423
d62a17ae 424 if (ri->num_nhs == 0)
425 goto done;
5adc2528 426
d62a17ae 427 if (ri->num_nhs == 1) {
428 nhi = &ri->nhs[0];
5adc2528 429
d62a17ae 430 if (nhi->gateway) {
92d6f769
K
431 if (nhi->type == NEXTHOP_TYPE_IPV4_IFINDEX
432 && ri->af == AF_INET6) {
433 ipv4_to_ipv4_mapped_ipv6(&ipv6,
434 nhi->gateway->ipv4);
435 nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY,
436 &ipv6, bytelen);
437 } else
438 nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY,
439 nhi->gateway, bytelen);
d62a17ae 440 }
5adc2528 441
d62a17ae 442 if (nhi->if_index) {
312a6bee
JU
443 nl_attr_put32(&req->n, in_buf_len, RTA_OIF,
444 nhi->if_index);
d62a17ae 445 }
5adc2528 446
9d21b7c6 447 encap = nhi->encap_info.encap_type;
58c3cdb9
DS
448 switch (encap) {
449 case FPM_NH_ENCAP_NONE:
450 case FPM_NH_ENCAP_MAX:
451 break;
452 case FPM_NH_ENCAP_VXLAN:
312a6bee
JU
453 nl_attr_put16(&req->n, in_buf_len, RTA_ENCAP_TYPE,
454 encap);
58c3cdb9 455 vxlan = &nhi->encap_info.vxlan_encap;
312a6bee
JU
456 nest = nl_attr_nest(&req->n, in_buf_len, RTA_ENCAP);
457 nl_attr_put32(&req->n, in_buf_len, VXLAN_VNI,
458 vxlan->vni);
459 nl_attr_nest_end(&req->n, nest);
58c3cdb9 460 break;
9d21b7c6
AD
461 }
462
d62a17ae 463 goto done;
5adc2528
AS
464 }
465
d62a17ae 466 /*
467 * Multipath case.
468 */
312a6bee 469 nest = nl_attr_nest(&req->n, in_buf_len, RTA_MULTIPATH);
d62a17ae 470
471 for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++) {
312a6bee 472 rtnh = nl_attr_rtnh(&req->n, in_buf_len);
d62a17ae 473 nhi = &ri->nhs[nexthop_num];
474
312a6bee
JU
475 if (nhi->gateway)
476 nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY,
477 nhi->gateway, bytelen);
d62a17ae 478
479 if (nhi->if_index) {
480 rtnh->rtnh_ifindex = nhi->if_index;
481 }
482
9d21b7c6 483 encap = nhi->encap_info.encap_type;
58c3cdb9
DS
484 switch (encap) {
485 case FPM_NH_ENCAP_NONE:
486 case FPM_NH_ENCAP_MAX:
487 break;
488 case FPM_NH_ENCAP_VXLAN:
312a6bee
JU
489 nl_attr_put16(&req->n, in_buf_len, RTA_ENCAP_TYPE,
490 encap);
58c3cdb9 491 vxlan = &nhi->encap_info.vxlan_encap;
312a6bee
JU
492 inner_nest =
493 nl_attr_nest(&req->n, in_buf_len, RTA_ENCAP);
494 nl_attr_put32(&req->n, in_buf_len, VXLAN_VNI,
495 vxlan->vni);
496 nl_attr_nest_end(&req->n, inner_nest);
58c3cdb9 497 break;
9d21b7c6
AD
498 }
499
312a6bee 500 nl_attr_rtnh_end(&req->n, rtnh);
5adc2528
AS
501 }
502
312a6bee
JU
503 nl_attr_nest_end(&req->n, nest);
504 assert(nest->rta_len > RTA_LENGTH(0));
5adc2528
AS
505
506done:
507
d62a17ae 508 if (ri->pref_src) {
312a6bee
JU
509 nl_attr_put(&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src,
510 bytelen);
d62a17ae 511 }
5adc2528 512
d62a17ae 513 assert(req->n.nlmsg_len < in_buf_len);
514 return req->n.nlmsg_len;
5adc2528
AS
515}
516
517/*
518 * zfpm_log_route_info
519 *
520 * Helper function to log the information in a route_info structure.
521 */
67ceb408
DS
522static void zfpm_log_route_info(struct netlink_route_info *ri,
523 const char *label)
5adc2528 524{
7cf19069 525 struct netlink_nh_info *nhi;
d62a17ae 526 unsigned int i;
9bcef951 527 char buf[PREFIX_STRLEN];
d62a17ae 528
5e9f9adb
DL
529 zfpm_debug("%s : %s %pFX, Proto: %s, Metric: %u", label,
530 nl_msg_type_to_str(ri->nlmsg_type), ri->prefix,
d62a17ae 531 nl_rtproto_to_str(ri->rtm_protocol),
532 ri->metric ? *ri->metric : 0);
533
534 for (i = 0; i < ri->num_nhs; i++) {
535 nhi = &ri->nhs[i];
9bcef951
MS
536
537 if (ri->af == AF_INET)
538 inet_ntop(AF_INET, &nhi->gateway, buf, sizeof(buf));
539 else
540 inet_ntop(AF_INET6, &nhi->gateway, buf, sizeof(buf));
541
9d21b7c6 542 zfpm_debug(" Intf: %u, Gateway: %s, Recursive: %s, Type: %s, Encap type: %s",
9bcef951 543 nhi->if_index, buf, nhi->recursive ? "yes" : "no",
9d21b7c6
AD
544 nexthop_type_to_str(nhi->type),
545 fpm_nh_encap_type_to_str(nhi->encap_info.encap_type)
546 );
d62a17ae 547 }
5adc2528
AS
548}
549
550/*
551 * zfpm_netlink_encode_route
552 *
553 * Create a netlink message corresponding to the given route in the
554 * given buffer space.
555 *
556 * Returns the number of bytes written to the buffer. 0 or a negative
557 * value indicates an error.
558 */
d62a17ae 559int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re,
560 char *in_buf, size_t in_buf_len)
5adc2528 561{
67ceb408 562 struct netlink_route_info ri_space, *ri;
5adc2528 563
d62a17ae 564 ri = &ri_space;
5adc2528 565
d62a17ae 566 if (!netlink_route_info_fill(ri, cmd, dest, re))
567 return 0;
5adc2528 568
15569c58 569 zfpm_log_route_info(ri, __func__);
5adc2528 570
d62a17ae 571 return netlink_route_info_encode(ri, in_buf, in_buf_len);
5adc2528 572}
ddfeb486 573
9da60d0a
AD
574/*
575 * zfpm_netlink_encode_mac
576 *
577 * Create a netlink message corresponding to the given MAC.
578 *
579 * Returns the number of bytes written to the buffer. 0 or a negative
580 * value indicates an error.
581 */
582int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf,
583 size_t in_buf_len)
584{
9da60d0a
AD
585 size_t buf_offset;
586
c5431822 587 struct macmsg {
9da60d0a
AD
588 struct nlmsghdr hdr;
589 struct ndmsg ndm;
590 char buf[0];
591 } *req;
592 req = (void *)in_buf;
593
c5431822 594 buf_offset = offsetof(struct macmsg, buf);
9da60d0a
AD
595 if (in_buf_len < buf_offset)
596 return 0;
597 memset(req, 0, buf_offset);
598
599 /* Construct nlmsg header */
600 req->hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
601 req->hdr.nlmsg_type = CHECK_FLAG(mac->fpm_flags, ZEBRA_MAC_DELETE_FPM) ?
602 RTM_DELNEIGH : RTM_NEWNEIGH;
603 req->hdr.nlmsg_flags = NLM_F_REQUEST;
604 if (req->hdr.nlmsg_type == RTM_NEWNEIGH)
605 req->hdr.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE);
606
607 /* Construct ndmsg */
608 req->ndm.ndm_family = AF_BRIDGE;
609 req->ndm.ndm_ifindex = mac->vxlan_if;
610
611 req->ndm.ndm_state = NUD_REACHABLE;
612 req->ndm.ndm_flags |= NTF_SELF | NTF_MASTER;
613 if (CHECK_FLAG(mac->zebra_flags,
614 (ZEBRA_MAC_STICKY | ZEBRA_MAC_REMOTE_DEF_GW)))
615 req->ndm.ndm_state |= NUD_NOARP;
616 else
617 req->ndm.ndm_flags |= NTF_EXT_LEARNED;
618
619 /* Add attributes */
312a6bee
JU
620 nl_attr_put(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6);
621 nl_attr_put(&req->hdr, in_buf_len, NDA_DST, &mac->r_vtep_ip, 4);
622 nl_attr_put32(&req->hdr, in_buf_len, NDA_MASTER, mac->svi_if);
623 nl_attr_put32(&req->hdr, in_buf_len, NDA_VNI, mac->vni);
9da60d0a
AD
624
625 assert(req->hdr.nlmsg_len < in_buf_len);
626
5e9f9adb 627 zfpm_debug("Tx %s family %s ifindex %u MAC %pEA DEST %pI4",
9da60d0a
AD
628 nl_msg_type_to_str(req->hdr.nlmsg_type),
629 nl_family_to_str(req->ndm.ndm_family), req->ndm.ndm_ifindex,
5e9f9adb 630 &mac->macaddr, &mac->r_vtep_ip);
9da60d0a
AD
631
632 return req->hdr.nlmsg_len;
633}
634
ddfeb486 635#endif /* HAVE_NETLINK */