]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rt_netlink.c
Merge remote-tracking branch 'origin/stable/3.0'
[mirror_frr.git] / zebra / rt_netlink.c
CommitLineData
718e3744 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
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
e52702f2 19 * 02111-1307, USA.
718e3744 20 */
21
22#include <zebra.h>
8ccc7e80 23#include <net/if_arp.h>
718e3744 24
25/* Hack for GNU libc version 2. */
26#ifndef MSG_TRUNC
27#define MSG_TRUNC 0x20
28#endif /* MSG_TRUNC */
29
30#include "linklist.h"
31#include "if.h"
32#include "log.h"
33#include "prefix.h"
34#include "connected.h"
35#include "table.h"
26e2ae36 36#include "memory.h"
4a1ab8e4 37#include "zebra_memory.h"
718e3744 38#include "rib.h"
e04ab74d 39#include "thread.h"
edd7c245 40#include "privs.h"
fb018d25 41#include "nexthop.h"
78104b9b 42#include "vrf.h"
5e6a74d8 43#include "vty.h"
40c7bdb0 44#include "mpls.h"
718e3744 45
46#include "zebra/zserv.h"
fe18ee2d 47#include "zebra/zebra_ns.h"
7c551956 48#include "zebra/zebra_vrf.h"
6621ca86 49#include "zebra/rt.h"
718e3744 50#include "zebra/redistribute.h"
51#include "zebra/interface.h"
52#include "zebra/debug.h"
12f6fb97 53#include "zebra/rtadv.h"
567b877d 54#include "zebra/zebra_ptm.h"
40c7bdb0 55#include "zebra/zebra_mpls.h"
1fdc9eae 56#include "zebra/kernel_netlink.h"
57#include "zebra/rt_netlink.h"
e3be0432
DS
58#include "zebra/zebra_mroute.h"
59
7021c425 60
40c7bdb0 61/* TODO - Temporary definitions, need to refine. */
62#ifndef AF_MPLS
63#define AF_MPLS 28
64#endif
65
66#ifndef RTA_VIA
c0f4be83 67#define RTA_VIA 18
40c7bdb0 68#endif
69
70#ifndef RTA_NEWDST
71#define RTA_NEWDST 19
72#endif
c0f4be83 73
74#ifndef RTA_ENCAP_TYPE
75#define RTA_ENCAP_TYPE 21
76#endif
77
78#ifndef RTA_ENCAP
79#define RTA_ENCAP 22
80#endif
81
113db945
DS
82#ifndef RTA_EXPIRES
83#define RTA_EXPIRES 23
84#endif
85
c0f4be83 86#ifndef LWTUNNEL_ENCAP_MPLS
87#define LWTUNNEL_ENCAP_MPLS 1
88#endif
89
90#ifndef MPLS_IPTUNNEL_DST
91#define MPLS_IPTUNNEL_DST 1
92#endif
52d8f0d8
DS
93
94#ifndef NDA_MASTER
95#define NDA_MASTER 9
96#endif
40c7bdb0 97/* End of temporary definitions */
98
99struct gw_family_t
100{
101 u_int16_t filler;
102 u_int16_t family;
103 union g_addr gate;
104};
105
12f6fb97
DS
106/*
107Pending: create an efficient table_id (in a tree/hash) based lookup)
108 */
109static vrf_id_t
110vrf_lookup_by_table (u_int32_t table_id)
111{
1a1a7065 112 struct vrf *vrf;
12f6fb97 113 struct zebra_vrf *zvrf;
12f6fb97 114
1a1a7065 115 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
12f6fb97 116 {
1a1a7065 117 if ((zvrf = vrf->info) == NULL ||
12f6fb97
DS
118 (zvrf->table_id != table_id))
119 continue;
120
661512bf 121 return zvrf_id (zvrf);
12f6fb97
DS
122 }
123
124 return VRF_DEFAULT;
125}
126
718e3744 127/* Looking up routing table by netlink interface. */
6072b24e 128static int
89a9069a
DS
129netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
130 ns_id_t ns_id, int startup)
718e3744 131{
132 int len;
133 struct rtmsg *rtm;
7021c425 134 struct rtattr *tb[RTA_MAX + 1];
718e3744 135 u_char flags = 0;
3b1098be 136 struct prefix p;
05737783 137 struct prefix_ipv6 src_p;
d552ed06 138 vrf_id_t vrf_id = VRF_DEFAULT;
7021c425 139
140 char anyaddr[16] = { 0 };
718e3744 141
05737783 142 int index = 0;
718e3744 143 int table;
05737783 144 int metric = 0;
c50ca33a 145 u_int32_t mtu = 0;
34195bf6 146
05737783
CF
147 void *dest = NULL;
148 void *gate = NULL;
149 void *prefsrc = NULL; /* IPv4 preferred source host address */
150 void *src = NULL; /* IPv6 srcdest source prefix */
718e3744 151
152 rtm = NLMSG_DATA (h);
153
89a9069a 154 if (startup && h->nlmsg_type != RTM_NEWROUTE)
718e3744 155 return 0;
89a9069a 156 if (startup && rtm->rtm_type != RTN_UNICAST)
718e3744 157 return 0;
158
7021c425 159 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
718e3744 160 if (len < 0)
161 return -1;
162
163 memset (tb, 0, sizeof tb);
164 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
165
166 if (rtm->rtm_flags & RTM_F_CLONED)
167 return 0;
168 if (rtm->rtm_protocol == RTPROT_REDIRECT)
169 return 0;
170 if (rtm->rtm_protocol == RTPROT_KERNEL)
171 return 0;
172
89a9069a
DS
173 if (!startup &&
174 rtm->rtm_protocol == RTPROT_ZEBRA &&
175 h->nlmsg_type == RTM_NEWROUTE)
176 return 0;
177
40c7bdb0 178 /* We don't care about change notifications for the MPLS table. */
179 /* TODO: Revisit this. */
180 if (rtm->rtm_family == AF_MPLS)
181 return 0;
182
ca46a78e 183 /* Table corresponding to route. */
184 if (tb[RTA_TABLE])
185 table = *(int *) RTA_DATA (tb[RTA_TABLE]);
186 else
187 table = rtm->rtm_table;
188
189 /* Map to VRF */
190 vrf_id = vrf_lookup_by_table(table);
191 if (vrf_id == VRF_DEFAULT)
192 {
193 if (!is_zebra_valid_kernel_table(table) &&
194 !is_zebra_main_routing_table(table))
195 return 0;
196 }
197
718e3744 198 /* Route which inserted by Zebra. */
199 if (rtm->rtm_protocol == RTPROT_ZEBRA)
200 flags |= ZEBRA_FLAG_SELFROUTE;
7021c425 201
718e3744 202 if (tb[RTA_OIF])
203 index = *(int *) RTA_DATA (tb[RTA_OIF]);
204
205 if (tb[RTA_DST])
206 dest = RTA_DATA (tb[RTA_DST]);
207 else
208 dest = anyaddr;
209
05737783
CF
210 if (tb[RTA_SRC])
211 src = RTA_DATA (tb[RTA_SRC]);
212 else
213 src = anyaddr;
214
7514fb77 215 if (tb[RTA_PREFSRC])
05737783 216 prefsrc = RTA_DATA (tb[RTA_PREFSRC]);
7514fb77 217
718e3744 218 if (tb[RTA_GATEWAY])
219 gate = RTA_DATA (tb[RTA_GATEWAY]);
220
c50ca33a
TT
221 if (h->nlmsg_type == RTM_NEWROUTE)
222 {
223 if (tb[RTA_PRIORITY])
224 metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
225
226 if (tb[RTA_METRICS])
227 {
228 struct rtattr *mxrta[RTAX_MAX+1];
229
230 memset (mxrta, 0, sizeof mxrta);
231 netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]),
232 RTA_PAYLOAD(tb[RTA_METRICS]));
233
234 if (mxrta[RTAX_MTU])
235 mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]);
236 }
237 }
26e2ae36 238
718e3744 239 if (rtm->rtm_family == AF_INET)
240 {
718e3744 241 p.family = AF_INET;
616368ed 242 memcpy (&p.u.prefix4, dest, 4);
718e3744 243 p.prefixlen = rtm->rtm_dst_len;
a2ca67d1
DS
244 }
245 else if (rtm->rtm_family == AF_INET6)
246 {
247 p.family = AF_INET6;
248 memcpy (&p.u.prefix6, dest, 16);
249 p.prefixlen = rtm->rtm_dst_len;
718e3744 250
a2ca67d1
DS
251 src_p.family = AF_INET6;
252 memcpy (&src_p.prefix, src, 16);
253 src_p.prefixlen = rtm->rtm_src_len;
254 }
05737783 255
a2ca67d1
DS
256 if (rtm->rtm_src_len != 0)
257 {
258 char buf[PREFIX_STRLEN];
259 zlog_warn ("unsupported IPv[4|6] sourcedest route (dest %s vrf %u)",
260 prefix2str (&p, buf, sizeof(buf)), vrf_id);
261 return 0;
262 }
263
264 if (IS_ZEBRA_DEBUG_KERNEL)
265 {
266 char buf[PREFIX_STRLEN];
267 char buf2[PREFIX_STRLEN];
268 zlog_debug ("%s %s%s%s vrf %u",
269 nl_msg_type_to_str (h->nlmsg_type),
270 prefix2str (&p, buf, sizeof(buf)),
271 src_p.prefixlen ? " from " : "",
272 src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "",
273 vrf_id);
274 }
718e3744 275
a2ca67d1
DS
276 afi_t afi = AFI_IP;
277 if (rtm->rtm_family == AF_INET6)
278 afi = AFI_IP6;
279
280 if (h->nlmsg_type == RTM_NEWROUTE)
281 {
282 if (!tb[RTA_MULTIPATH])
283 rib_add (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL,
284 0, flags, &p, NULL, gate, prefsrc, index,
285 table, metric, mtu, 0);
286 else
26e2ae36 287 {
a2ca67d1
DS
288 /* This is a multipath route */
289
290 struct rib *rib;
291 struct rtnexthop *rtnh =
292 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
293
294 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
295
296 rib = XCALLOC (MTYPE_RIB, sizeof (struct rib));
297 rib->type = ZEBRA_ROUTE_KERNEL;
298 rib->distance = 0;
299 rib->flags = flags;
300 rib->metric = metric;
301 rib->mtu = mtu;
302 rib->vrf_id = vrf_id;
303 rib->table = table;
304 rib->nexthop_num = 0;
305 rib->uptime = time (NULL);
306
307 for (;;)
26e2ae36 308 {
a2ca67d1
DS
309 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
310 break;
26e2ae36 311
a2ca67d1
DS
312 index = rtnh->rtnh_ifindex;
313 gate = 0;
314 if (rtnh->rtnh_len > sizeof (*rtnh))
315 {
316 memset (tb, 0, sizeof (tb));
317 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
318 rtnh->rtnh_len - sizeof (*rtnh));
319 if (tb[RTA_GATEWAY])
320 gate = RTA_DATA (tb[RTA_GATEWAY]);
321 }
26e2ae36 322
a2ca67d1
DS
323 if (gate)
324 {
325 if (rtm->rtm_family == AF_INET)
26e2ae36
JB
326 {
327 if (index)
05737783 328 rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index);
26e2ae36 329 else
05737783 330 rib_nexthop_ipv4_add (rib, gate, prefsrc);
26e2ae36 331 }
a2ca67d1
DS
332 else if (rtm->rtm_family == AF_INET6)
333 {
334 if (index)
335 rib_nexthop_ipv6_ifindex_add (rib, gate, index);
336 else
337 rib_nexthop_ipv6_add (rib,gate);
338 }
1fdc9eae 339 }
1fdc9eae 340 else
a2ca67d1 341 rib_nexthop_ifindex_add (rib, index);
26e2ae36 342
a2ca67d1
DS
343 len -= NLMSG_ALIGN(rtnh->rtnh_len);
344 rtnh = RTNH_NEXT(rtnh);
345 }
05737783 346
a2ca67d1
DS
347 zserv_nexthop_num_warn(__func__, (const struct prefix *)&p,
348 rib->nexthop_num);
349 if (rib->nexthop_num == 0)
350 XFREE (MTYPE_RIB, rib);
351 else
352 rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib);
7021c425 353 }
718e3744 354 }
a2ca67d1 355 else
2f8685a2
DS
356 {
357 if (!tb[RTA_MULTIPATH])
358 rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
359 &p, NULL, gate, index, table);
360 else
361 {
362 struct rtnexthop *rtnh =
363 (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]);
364
365 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
366
367 for (;;)
368 {
369 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
370 break;
371
372 gate = NULL;
373 if (rtnh->rtnh_len > sizeof (*rtnh))
374 {
375 memset (tb, 0, sizeof (tb));
376 netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh),
377 rtnh->rtnh_len - sizeof (*rtnh));
378 if (tb[RTA_GATEWAY])
379 gate = RTA_DATA (tb[RTA_GATEWAY]);
380 }
381
382 if (gate)
383 rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags,
384 &p, NULL, gate, index, table);
385
386 len -= NLMSG_ALIGN(rtnh->rtnh_len);
387 rtnh = RTNH_NEXT(rtnh);
388 }
389 }
390 }
718e3744 391
392 return 0;
393}
394
e3be0432
DS
395static struct mcast_route_data *mroute = NULL;
396
565fdc75
DS
397static int
398netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h,
936ebf0a 399 ns_id_t ns_id, int startup)
565fdc75
DS
400{
401 int len;
402 struct rtmsg *rtm;
403 struct rtattr *tb[RTA_MAX + 1];
e3be0432
DS
404 struct mcast_route_data *m;
405 struct mcast_route_data mr;
90d82769
DS
406 int iif = 0;
407 int count;
408 int oif[256];
409 int oif_count = 0;
410 char sbuf[40];
411 char gbuf[40];
412 char oif_list[256] = "\0";
90d82769 413 vrf_id_t vrf = ns_id;
565fdc75 414
e3be0432
DS
415 if (mroute)
416 m = mroute;
417 else
f0242f68
DS
418 {
419 memset (&mr, 0, sizeof (mr));
420 m = &mr;
421 }
e3be0432 422
565fdc75
DS
423 rtm = NLMSG_DATA (h);
424
425 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
426
427 memset (tb, 0, sizeof tb);
428 netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len);
429
90d82769
DS
430 if (tb[RTA_IIF])
431 iif = *(int *)RTA_DATA (tb[RTA_IIF]);
432
433 if (tb[RTA_SRC])
e3be0432 434 m->sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]);
90d82769
DS
435
436 if (tb[RTA_DST])
e3be0432 437 m->sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]);
90d82769 438
113db945 439 if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES])
e3be0432 440 m->lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]);
90d82769
DS
441
442 if (tb[RTA_MULTIPATH])
443 {
444 struct rtnexthop *rtnh =
445 (struct rtnexthop *)RTA_DATA (tb[RTA_MULTIPATH]);
446
447 len = RTA_PAYLOAD (tb[RTA_MULTIPATH]);
448 for (;;)
449 {
450 if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len)
451 break;
452
453 oif[oif_count] = rtnh->rtnh_ifindex;
454 oif_count++;
455
456 len -= NLMSG_ALIGN (rtnh->rtnh_len);
457 rtnh = RTNH_NEXT (rtnh);
458 }
459 }
460
461 if (IS_ZEBRA_DEBUG_KERNEL)
462 {
82d64e8e 463 struct interface *ifp;
e3be0432
DS
464 strcpy (sbuf, inet_ntoa (m->sg.src));
465 strcpy (gbuf, inet_ntoa (m->sg.grp));
90d82769
DS
466 for (count = 0; count < oif_count; count++)
467 {
7e2b7603 468 ifp = if_lookup_by_index (oif[count], vrf);
90d82769
DS
469 char temp[256];
470
471 sprintf (temp, "%s ", ifp->name);
472 strcat (oif_list, temp);
473 }
7e2b7603 474 ifp = if_lookup_by_index (iif, vrf);
82d64e8e
DS
475 zlog_debug ("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld",
476 nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, ifp->name, oif_list, m->lastused);
90d82769 477 }
565fdc75
DS
478 return 0;
479}
480
481int
482netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h,
936ebf0a 483 ns_id_t ns_id, int startup)
565fdc75
DS
484{
485 int len;
486 vrf_id_t vrf_id = ns_id;
487 struct rtmsg *rtm;
488
489 rtm = NLMSG_DATA (h);
490
491 if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE))
492 {
493 /* If this is not route add/delete message print warning. */
494 zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id);
495 return 0;
496 }
497
498 /* Connected route. */
499 if (IS_ZEBRA_DEBUG_KERNEL)
500 zlog_debug ("%s %s %s proto %s vrf %u",
90d82769
DS
501 nl_msg_type_to_str (h->nlmsg_type),
502 nl_family_to_str (rtm->rtm_family),
503 nl_rttype_to_str (rtm->rtm_type),
565fdc75 504 nl_rtproto_to_str (rtm->rtm_protocol),
90d82769 505 vrf_id);
565fdc75
DS
506
507 /* We don't care about change notifications for the MPLS table. */
508 /* TODO: Revisit this. */
509 if (rtm->rtm_family == AF_MPLS)
510 return 0;
511
512 len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg));
513 if (len < 0)
514 return -1;
515
516 switch (rtm->rtm_type)
517 {
518 case RTN_UNICAST:
936ebf0a 519 netlink_route_change_read_unicast (snl, h, ns_id, startup);
565fdc75
DS
520 break;
521 case RTN_MULTICAST:
936ebf0a 522 netlink_route_change_read_multicast (snl, h, ns_id, startup);
565fdc75
DS
523 break;
524 default:
525 return 0;
526 break;
527 }
528
529 return 0;
530}
531
718e3744 532/* Routing table read function using netlink interface. Only called
533 bootstrap time. */
534int
12f6fb97 535netlink_route_read (struct zebra_ns *zns)
718e3744 536{
537 int ret;
7021c425 538
718e3744 539 /* Get IPv4 routing table. */
12f6fb97 540 ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd);
718e3744 541 if (ret < 0)
542 return ret;
89a9069a 543 ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
718e3744 544 if (ret < 0)
545 return ret;
546
718e3744 547 /* Get IPv6 routing table. */
12f6fb97 548 ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd);
718e3744 549 if (ret < 0)
550 return ret;
89a9069a 551 ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1);
718e3744 552 if (ret < 0)
553 return ret;
718e3744 554
555 return 0;
556}
557
40c7bdb0 558static void
559_netlink_route_nl_add_gateway_info (u_char route_family, u_char gw_family,
560 struct nlmsghdr *nlmsg,
561 size_t req_size, int bytelen,
562 struct nexthop *nexthop)
563{
564 if (route_family == AF_MPLS)
565 {
566 struct gw_family_t gw_fam;
567
568 gw_fam.family = gw_family;
569 if (gw_family == AF_INET)
570 memcpy (&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
571 else
572 memcpy (&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
573 addattr_l (nlmsg, req_size, RTA_VIA, &gw_fam.family, bytelen+2);
574 }
575 else
576 {
577 if (gw_family == AF_INET)
578 addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen);
579 else
580 addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen);
581 }
582}
583
584static void
585_netlink_route_rta_add_gateway_info (u_char route_family, u_char gw_family,
586 struct rtattr *rta, struct rtnexthop *rtnh,
587 size_t req_size, int bytelen,
588 struct nexthop *nexthop)
589{
590 if (route_family == AF_MPLS)
591 {
592 struct gw_family_t gw_fam;
593
594 gw_fam.family = gw_family;
595 if (gw_family == AF_INET)
596 memcpy (&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen);
597 else
598 memcpy (&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen);
599 rta_addattr_l (rta, req_size, RTA_VIA, &gw_fam.family, bytelen+2);
600 rtnh->rtnh_len += RTA_LENGTH (bytelen + 2);
601 }
602 else
603 {
604 if (gw_family == AF_INET)
605 rta_addattr_l (rta, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen);
606 else
607 rta_addattr_l (rta, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen);
608 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
609 }
610}
611
fa713d9e
CF
612/* This function takes a nexthop as argument and adds
613 * the appropriate netlink attributes to an existing
614 * netlink message.
615 *
616 * @param routedesc: Human readable description of route type
617 * (direct/recursive, single-/multipath)
618 * @param bytelen: Length of addresses in bytes.
619 * @param nexthop: Nexthop information
620 * @param nlmsg: nlmsghdr structure to fill in.
621 * @param req_size: The size allocated for the message.
622 */
623static void
624_netlink_route_build_singlepath(
625 const char *routedesc,
626 int bytelen,
627 struct nexthop *nexthop,
628 struct nlmsghdr *nlmsg,
e8d3d299 629 struct rtmsg *rtmsg,
c52ef59f
DS
630 size_t req_size,
631 int cmd)
fa713d9e 632{
c0f4be83 633 struct nexthop_label *nh_label;
634 mpls_lse_t out_lse[MPLS_MAX_LABELS];
40c7bdb0 635 char label_buf[100];
5c610faf
DS
636
637 if (rtmsg->rtm_family == AF_INET &&
638 (nexthop->type == NEXTHOP_TYPE_IPV6
5c610faf
DS
639 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX))
640 {
641 char buf[16] = "169.254.0.1";
642 struct in_addr ipv4_ll;
643
644 inet_pton (AF_INET, buf, &ipv4_ll);
645 rtmsg->rtm_flags |= RTNH_F_ONLINK;
646 addattr_l (nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4);
647 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
648
fb5d585c 649 if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
650 addattr_l (nlmsg, req_size, RTA_PREFSRC,
651 &nexthop->rmap_src.ipv4, bytelen);
652 else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE))
653 addattr_l (nlmsg, req_size, RTA_PREFSRC,
654 &nexthop->src.ipv4, bytelen);
655
5c610faf
DS
656 if (IS_ZEBRA_DEBUG_KERNEL)
657 zlog_debug(" 5549: _netlink_route_build_singlepath() (%s): "
658 "nexthop via %s if %u",
659 routedesc, buf, nexthop->ifindex);
660 return;
661 }
662
40c7bdb0 663 label_buf[0] = '\0';
c0f4be83 664 /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
665 * (in the case of LER)
666 */
667 nh_label = nexthop->nh_label;
40c7bdb0 668 if (rtmsg->rtm_family == AF_MPLS)
669 {
c0f4be83 670 assert (nh_label);
671 assert (nh_label->num_labels == 1);
672 }
40c7bdb0 673
c0f4be83 674 if (nh_label && nh_label->num_labels)
675 {
676 int i, num_labels = 0;
677 u_int32_t bos;
678 char label_buf1[20];
e52702f2 679
c0f4be83 680 for (i = 0; i < nh_label->num_labels; i++)
40c7bdb0 681 {
c0f4be83 682 if (nh_label->label[i] != MPLS_IMP_NULL_LABEL)
683 {
684 bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0);
685 out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos);
686 if (!num_labels)
687 sprintf (label_buf, "label %d", nh_label->label[i]);
688 else
689 {
690 sprintf (label_buf1, "/%d", nh_label->label[i]);
691 strcat (label_buf, label_buf1);
692 }
693 num_labels++;
694 }
695 }
696 if (num_labels)
697 {
698 if (rtmsg->rtm_family == AF_MPLS)
699 addattr_l (nlmsg, req_size, RTA_NEWDST,
700 &out_lse, num_labels * sizeof(mpls_lse_t));
701 else
702 {
703 struct rtattr *nest;
704 u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
705
706 addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE,
707 &encap, sizeof (u_int16_t));
708 nest = addattr_nest(nlmsg, req_size, RTA_ENCAP);
709 addattr_l (nlmsg, req_size, MPLS_IPTUNNEL_DST,
710 &out_lse, num_labels * sizeof(mpls_lse_t));
711 addattr_nest_end(nlmsg, nest);
712 }
40c7bdb0 713 }
714 }
715
e8d3d299
CF
716 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
717 rtmsg->rtm_flags |= RTNH_F_ONLINK;
5c610faf 718
fa713d9e
CF
719 if (nexthop->type == NEXTHOP_TYPE_IPV4
720 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
721 {
659b52a8
DS
722 /* Send deletes to the kernel without specifying the next-hop */
723 if (cmd != RTM_DELROUTE)
724 _netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET, nlmsg,
725 req_size, bytelen, nexthop);
c52ef59f 726
0aabccc0
DD
727 if (cmd == RTM_NEWROUTE)
728 {
729 if (nexthop->rmap_src.ipv4.s_addr)
730 addattr_l (nlmsg, req_size, RTA_PREFSRC,
731 &nexthop->rmap_src.ipv4, bytelen);
732 else if (nexthop->src.ipv4.s_addr)
733 addattr_l (nlmsg, req_size, RTA_PREFSRC,
734 &nexthop->src.ipv4, bytelen);
735 }
fa713d9e
CF
736
737 if (IS_ZEBRA_DEBUG_KERNEL)
738 zlog_debug("netlink_route_multipath() (%s): "
40c7bdb0 739 "nexthop via %s %s if %u",
fa713d9e
CF
740 routedesc,
741 inet_ntoa (nexthop->gate.ipv4),
40c7bdb0 742 label_buf, nexthop->ifindex);
fa713d9e 743 }
fa713d9e 744 if (nexthop->type == NEXTHOP_TYPE_IPV6
fa713d9e
CF
745 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
746 {
40c7bdb0 747 _netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET6, nlmsg,
748 req_size, bytelen, nexthop);
fa713d9e 749
0aabccc0
DD
750 if (cmd == RTM_NEWROUTE)
751 {
752 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
753 addattr_l (nlmsg, req_size, RTA_PREFSRC,
754 &nexthop->rmap_src.ipv6, bytelen);
755 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
756 addattr_l (nlmsg, req_size, RTA_PREFSRC,
757 &nexthop->src.ipv6, bytelen);
758 }
759
fa713d9e
CF
760 if (IS_ZEBRA_DEBUG_KERNEL)
761 zlog_debug("netlink_route_multipath() (%s): "
40c7bdb0 762 "nexthop via %s %s if %u",
fa713d9e
CF
763 routedesc,
764 inet6_ntoa (nexthop->gate.ipv6),
40c7bdb0 765 label_buf, nexthop->ifindex);
fa713d9e 766 }
fa713d9e 767 if (nexthop->type == NEXTHOP_TYPE_IFINDEX
fa713d9e
CF
768 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
769 {
770 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
771
0aabccc0
DD
772 if (cmd == RTM_NEWROUTE)
773 {
774 if (nexthop->rmap_src.ipv4.s_addr)
775 addattr_l (nlmsg, req_size, RTA_PREFSRC,
776 &nexthop->rmap_src.ipv4, bytelen);
777 else if (nexthop->src.ipv4.s_addr)
778 addattr_l (nlmsg, req_size, RTA_PREFSRC,
779 &nexthop->src.ipv4, bytelen);
780 }
fa713d9e
CF
781
782 if (IS_ZEBRA_DEBUG_KERNEL)
783 zlog_debug("netlink_route_multipath() (%s): "
784 "nexthop via if %u", routedesc, nexthop->ifindex);
785 }
786
3ee39b5b 787 if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
fa713d9e
CF
788 {
789 addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex);
790
0aabccc0
DD
791 if (cmd == RTM_NEWROUTE)
792 {
793 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
794 addattr_l (nlmsg, req_size, RTA_PREFSRC,
795 &nexthop->rmap_src.ipv6, bytelen);
796 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
797 addattr_l (nlmsg, req_size, RTA_PREFSRC,
798 &nexthop->src.ipv6, bytelen);
799 }
800
fa713d9e
CF
801 if (IS_ZEBRA_DEBUG_KERNEL)
802 zlog_debug("netlink_route_multipath() (%s): "
803 "nexthop via if %u", routedesc, nexthop->ifindex);
804 }
805}
806
807/* This function takes a nexthop as argument and
808 * appends to the given rtattr/rtnexthop pair the
809 * representation of the nexthop. If the nexthop
810 * defines a preferred source, the src parameter
811 * will be modified to point to that src, otherwise
812 * it will be kept unmodified.
813 *
814 * @param routedesc: Human readable description of route type
815 * (direct/recursive, single-/multipath)
816 * @param bytelen: Length of addresses in bytes.
817 * @param nexthop: Nexthop information
818 * @param rta: rtnetlink attribute structure
819 * @param rtnh: pointer to an rtnetlink nexthop structure
820 * @param src: pointer pointing to a location where
821 * the prefsrc should be stored.
822 */
823static void
824_netlink_route_build_multipath(
825 const char *routedesc,
826 int bytelen,
827 struct nexthop *nexthop,
828 struct rtattr *rta,
829 struct rtnexthop *rtnh,
5c610faf
DS
830 struct rtmsg *rtmsg,
831 union g_addr **src)
fa713d9e 832{
c0f4be83 833 struct nexthop_label *nh_label;
834 mpls_lse_t out_lse[MPLS_MAX_LABELS];
40c7bdb0 835 char label_buf[100];
836
fa713d9e
CF
837 rtnh->rtnh_len = sizeof (*rtnh);
838 rtnh->rtnh_flags = 0;
839 rtnh->rtnh_hops = 0;
840 rta->rta_len += rtnh->rtnh_len;
841
5c610faf
DS
842 if (rtmsg->rtm_family == AF_INET &&
843 (nexthop->type == NEXTHOP_TYPE_IPV6
5c610faf
DS
844 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX))
845 {
846 char buf[16] = "169.254.0.1";
847 struct in_addr ipv4_ll;
848
849 inet_pton (AF_INET, buf, &ipv4_ll);
850 bytelen = 4;
851 rtnh->rtnh_flags |= RTNH_F_ONLINK;
852 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY,
853 &ipv4_ll, bytelen);
854 rtnh->rtnh_len += sizeof (struct rtattr) + bytelen;
855 rtnh->rtnh_ifindex = nexthop->ifindex;
856
fb5d585c 857 if (nexthop->rmap_src.ipv4.s_addr)
858 *src = &nexthop->rmap_src;
859 else if (nexthop->src.ipv4.s_addr)
860 *src = &nexthop->src;
861
5c610faf
DS
862 if (IS_ZEBRA_DEBUG_KERNEL)
863 zlog_debug(" 5549: netlink_route_build_multipath() (%s): "
864 "nexthop via %s if %u",
865 routedesc, buf, nexthop->ifindex);
866 return;
867 }
868
40c7bdb0 869 label_buf[0] = '\0';
c0f4be83 870 /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
871 * (in the case of LER)
872 */
873 nh_label = nexthop->nh_label;
40c7bdb0 874 if (rtmsg->rtm_family == AF_MPLS)
875 {
c0f4be83 876 assert (nh_label);
877 assert (nh_label->num_labels == 1);
878 }
879
880 if (nh_label && nh_label->num_labels)
881 {
882 int i, num_labels = 0;
883 u_int32_t bos;
884 char label_buf1[20];
40c7bdb0 885
c0f4be83 886 for (i = 0; i < nh_label->num_labels; i++)
40c7bdb0 887 {
c0f4be83 888 if (nh_label->label[i] != MPLS_IMP_NULL_LABEL)
889 {
890 bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0);
891 out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos);
892 if (!num_labels)
893 sprintf (label_buf, "label %d", nh_label->label[i]);
894 else
895 {
896 sprintf (label_buf1, "/%d", nh_label->label[i]);
897 strcat (label_buf, label_buf1);
898 }
899 num_labels++;
900 }
901 }
902 if (num_labels)
903 {
904 if (rtmsg->rtm_family == AF_MPLS)
905 {
906 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_NEWDST,
907 &out_lse, num_labels * sizeof(mpls_lse_t));
908 rtnh->rtnh_len += RTA_LENGTH (num_labels * sizeof(mpls_lse_t));
909 }
910 else
911 {
912 struct rtattr *nest;
913 u_int16_t encap = LWTUNNEL_ENCAP_MPLS;
914 int len = rta->rta_len;
915
916 rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE,
917 &encap, sizeof (u_int16_t));
918 nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP);
919 rta_addattr_l (rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST,
920 &out_lse, num_labels * sizeof(mpls_lse_t));
921 rta_nest_end(rta, nest);
922 rtnh->rtnh_len += rta->rta_len - len;
923 }
40c7bdb0 924 }
925 }
5c610faf 926
e8d3d299
CF
927 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK))
928 rtnh->rtnh_flags |= RTNH_F_ONLINK;
929
fa713d9e
CF
930 if (nexthop->type == NEXTHOP_TYPE_IPV4
931 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
932 {
40c7bdb0 933 _netlink_route_rta_add_gateway_info (rtmsg->rtm_family, AF_INET, rta,
934 rtnh, NL_PKT_BUF_SIZE, bytelen, nexthop);
c52ef59f
DS
935 if (nexthop->rmap_src.ipv4.s_addr)
936 *src = &nexthop->rmap_src;
937 else if (nexthop->src.ipv4.s_addr)
938 *src = &nexthop->src;
fa713d9e
CF
939
940 if (IS_ZEBRA_DEBUG_KERNEL)
941 zlog_debug("netlink_route_multipath() (%s): "
40c7bdb0 942 "nexthop via %s %s if %u",
fa713d9e
CF
943 routedesc,
944 inet_ntoa (nexthop->gate.ipv4),
40c7bdb0 945 label_buf, nexthop->ifindex);
fa713d9e 946 }
fa713d9e 947 if (nexthop->type == NEXTHOP_TYPE_IPV6
fa713d9e
CF
948 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
949 {
40c7bdb0 950 _netlink_route_rta_add_gateway_info (rtmsg->rtm_family, AF_INET6, rta,
951 rtnh, NL_PKT_BUF_SIZE, bytelen, nexthop);
0aabccc0
DD
952
953 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
954 *src = &nexthop->rmap_src;
955 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
956 *src = &nexthop->src;
957
fa713d9e
CF
958 if (IS_ZEBRA_DEBUG_KERNEL)
959 zlog_debug("netlink_route_multipath() (%s): "
40c7bdb0 960 "nexthop via %s %s if %u",
fa713d9e
CF
961 routedesc,
962 inet6_ntoa (nexthop->gate.ipv6),
40c7bdb0 963 label_buf, nexthop->ifindex);
fa713d9e 964 }
fa713d9e
CF
965 /* ifindex */
966 if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX
3ee39b5b 967 || nexthop->type == NEXTHOP_TYPE_IFINDEX)
fa713d9e
CF
968 {
969 rtnh->rtnh_ifindex = nexthop->ifindex;
c52ef59f
DS
970
971 if (nexthop->rmap_src.ipv4.s_addr)
972 *src = &nexthop->rmap_src;
973 else if (nexthop->src.ipv4.s_addr)
fa713d9e 974 *src = &nexthop->src;
c52ef59f 975
fa713d9e
CF
976 if (IS_ZEBRA_DEBUG_KERNEL)
977 zlog_debug("netlink_route_multipath() (%s): "
978 "nexthop via if %u", routedesc, nexthop->ifindex);
979 }
3ee39b5b 980 else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
fa713d9e
CF
981 {
982 rtnh->rtnh_ifindex = nexthop->ifindex;
983
984 if (IS_ZEBRA_DEBUG_KERNEL)
985 zlog_debug("netlink_route_multipath() (%s): "
986 "nexthop via if %u", routedesc, nexthop->ifindex);
987 }
988 else
989 {
990 rtnh->rtnh_ifindex = 0;
991 }
992}
993
40c7bdb0 994static inline void
995_netlink_mpls_build_singlepath(
996 const char *routedesc,
997 zebra_nhlfe_t *nhlfe,
998 struct nlmsghdr *nlmsg,
999 struct rtmsg *rtmsg,
1000 size_t req_size,
1001 int cmd)
1002{
1003 int bytelen;
1004 u_char family;
1005
1006 family = NHLFE_FAMILY (nhlfe);
1007 bytelen = (family == AF_INET ? 4 : 16);
1008 _netlink_route_build_singlepath(routedesc, bytelen, nhlfe->nexthop,
1009 nlmsg, rtmsg, req_size, cmd);
1010}
1011
1012
1013static inline void
1014_netlink_mpls_build_multipath(
1015 const char *routedesc,
1016 zebra_nhlfe_t *nhlfe,
1017 struct rtattr *rta,
1018 struct rtnexthop *rtnh,
1019 struct rtmsg *rtmsg,
1020 union g_addr **src)
1021{
1022 int bytelen;
1023 u_char family;
1024
1025 family = NHLFE_FAMILY (nhlfe);
1026 bytelen = (family == AF_INET ? 4 : 16);
1027 _netlink_route_build_multipath(routedesc, bytelen, nhlfe->nexthop,
1028 rta, rtnh, rtmsg, src);
1029}
1030
1031
fa713d9e
CF
1032/* Log debug information for netlink_route_multipath
1033 * if debug logging is enabled.
1034 *
1035 * @param cmd: Netlink command which is to be processed
1036 * @param p: Prefix for which the change is due
1037 * @param nexthop: Nexthop which is currently processed
1038 * @param routedesc: Semantic annotation for nexthop
1039 * (recursive, multipath, etc.)
1040 * @param family: Address family which the change concerns
1041 */
1042static void
1043_netlink_route_debug(
1044 int cmd,
1045 struct prefix *p,
1046 struct nexthop *nexthop,
1047 const char *routedesc,
8f7d9fc0
FL
1048 int family,
1049 struct zebra_vrf *zvrf)
fa713d9e
CF
1050{
1051 if (IS_ZEBRA_DEBUG_KERNEL)
1052 {
35d921cc
TT
1053 char buf[PREFIX_STRLEN];
1054 zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s",
1055 routedesc,
1fdc9eae 1056 nl_msg_type_to_str (cmd),
661512bf 1057 prefix2str (p, buf, sizeof(buf)), zvrf_id (zvrf),
40c7bdb0 1058 (nexthop) ? nexthop_type_to_str (nexthop->type) : "UNK");
fa713d9e 1059 }
e52702f2 1060 }
fa713d9e 1061
40c7bdb0 1062static void
1063_netlink_mpls_debug(
1064 int cmd,
1065 u_int32_t label,
1066 const char *routedesc)
1067{
1068 if (IS_ZEBRA_DEBUG_KERNEL)
1069 zlog_debug ("netlink_mpls_multipath() (%s): %s %u/20",
1fdc9eae 1070 routedesc, nl_msg_type_to_str (cmd), label);
fa713d9e
CF
1071}
1072
6b8a5694 1073static int
1bb6e9b7 1074netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen)
5c610faf
DS
1075{
1076 struct {
1077 struct nlmsghdr n;
1078 struct ndmsg ndm;
1079 char buf[256];
1080 } req;
1081
fe18ee2d 1082 struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
8f7d9fc0 1083
5c610faf
DS
1084 memset(&req.n, 0, sizeof(req.n));
1085 memset(&req.ndm, 0, sizeof(req.ndm));
1086
1087 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
1088 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1089 req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH
1090 req.ndm.ndm_family = AF_INET;
1091 req.ndm.ndm_state = NUD_PERMANENT;
1092 req.ndm.ndm_ifindex = ifindex;
1093 req.ndm.ndm_type = RTN_UNICAST;
1094
1095 addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4);
1096 addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen);
1097
936ebf0a 1098 return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
5c610faf
DS
1099}
1100
718e3744 1101/* Routing table change via netlink interface. */
6ae24471 1102/* Update flag indicates whether this is a "replace" or not. */
6072b24e 1103static int
05737783
CF
1104netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p,
1105 struct rib *rib, int update)
718e3744 1106{
1107 int bytelen;
1108 struct sockaddr_nl snl;
fa713d9e
CF
1109 struct nexthop *nexthop = NULL, *tnexthop;
1110 int recursing;
37fe7731 1111 unsigned int nexthop_num;
718e3744 1112 int discard;
be717a0a 1113 int family = PREFIX_FAMILY(p);
fa713d9e 1114 const char *routedesc;
c52ef59f
DS
1115 int setsrc = 0;
1116 union g_addr src;
718e3744 1117
7021c425 1118 struct
718e3744 1119 {
1120 struct nlmsghdr n;
1121 struct rtmsg r;
3cadc0cd 1122 char buf[NL_PKT_BUF_SIZE];
718e3744 1123 } req;
1124
fe18ee2d 1125 struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
8f7d9fc0
FL
1126 struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id);
1127
a4c06dec 1128 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
718e3744 1129
1130 bytelen = (family == AF_INET ? 4 : 16);
1131
1132 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1133 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
6ae24471
DS
1134 if ((cmd == RTM_NEWROUTE) && update)
1135 req.n.nlmsg_flags |= NLM_F_REPLACE;
718e3744 1136 req.n.nlmsg_type = cmd;
1137 req.r.rtm_family = family;
718e3744 1138 req.r.rtm_dst_len = p->prefixlen;
05737783 1139 req.r.rtm_src_len = src_p ? src_p->prefixlen : 0;
40da2216
TT
1140 req.r.rtm_protocol = RTPROT_ZEBRA;
1141 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
718e3744 1142
7021c425 1143 if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT))
718e3744 1144 discard = 1;
1145 else
1146 discard = 0;
1147
7021c425 1148 if (cmd == RTM_NEWROUTE)
718e3744 1149 {
7021c425 1150 if (discard)
595db7f1 1151 {
1152 if (rib->flags & ZEBRA_FLAG_BLACKHOLE)
1153 req.r.rtm_type = RTN_BLACKHOLE;
1154 else if (rib->flags & ZEBRA_FLAG_REJECT)
1155 req.r.rtm_type = RTN_UNREACHABLE;
7021c425 1156 else
1157 assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */
1158 }
595db7f1 1159 else
7021c425 1160 req.r.rtm_type = RTN_UNICAST;
718e3744 1161 }
1162
1163 addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen);
05737783
CF
1164 if (src_p)
1165 addattr_l (&req.n, sizeof req, RTA_SRC, &src_p->u.prefix, bytelen);
718e3744 1166
1167 /* Metric. */
1f5705f0
DS
1168 /* Hardcode the metric for all routes coming from zebra. Metric isn't used
1169 * either by the kernel or by zebra. Its purely for calculating best path(s)
1170 * by the routing protocol and for communicating with protocol peers.
1171 */
1172 addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC);
718e3744 1173
ca46a78e 1174 /* Table corresponding to this route. */
1175 if (rib->table < 256)
1176 req.r.rtm_table = rib->table;
1177 else
1178 {
1179 req.r.rtm_table = RT_TABLE_UNSPEC;
1180 addattr32(&req.n, sizeof req, RTA_TABLE, rib->table);
1181 }
1182
c50ca33a
TT
1183 if (rib->mtu || rib->nexthop_mtu)
1184 {
1185 char buf[NL_PKT_BUF_SIZE];
1186 struct rtattr *rta = (void *) buf;
1187 u_int32_t mtu = rib->mtu;
1188 if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu))
1189 mtu = rib->nexthop_mtu;
1190 rta->rta_type = RTA_METRICS;
1191 rta->rta_len = RTA_LENGTH(0);
1192 rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu);
1193 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta),
1194 RTA_PAYLOAD (rta));
1195 }
1196
718e3744 1197 if (discard)
1198 {
1199 if (cmd == RTM_NEWROUTE)
fa713d9e
CF
1200 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1201 {
1202 /* We shouldn't encounter recursive nexthops on discard routes,
1203 * but it is probably better to handle that case correctly anyway.
1204 */
1205 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1206 continue;
fa713d9e 1207 }
718e3744 1208 goto skip;
1209 }
1210
fa713d9e
CF
1211 /* Count overall nexthops so we can decide whether to use singlepath
1212 * or multipath case. */
1213 nexthop_num = 0;
1214 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
1215 {
1216 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
1217 continue;
1218 if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1219 continue;
1220 if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
1221 continue;
1222
1223 nexthop_num++;
1224 }
1225
1226 /* Singlepath case. */
37fe7731 1227 if (nexthop_num == 1 || multipath_num == 1)
718e3744 1228 {
fa713d9e
CF
1229 nexthop_num = 0;
1230 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
7021c425 1231 {
fa713d9e 1232 if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
c52ef59f 1233 {
c52ef59f
DS
1234 if (!setsrc)
1235 {
0aabccc0
DD
1236 if (family == AF_INET)
1237 {
1238 if (nexthop->rmap_src.ipv4.s_addr != 0)
1239 {
1240 src.ipv4 = nexthop->rmap_src.ipv4;
1241 setsrc = 1;
1242 }
1243 else if (nexthop->src.ipv4.s_addr != 0)
1244 {
1245 src.ipv4 = nexthop->src.ipv4;
1246 setsrc = 1;
1247 }
1248 }
1249 else if (family == AF_INET6)
1250 {
1251 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
1252 {
1253 src.ipv6 = nexthop->rmap_src.ipv6;
1254 setsrc = 1;
1255 }
1256 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
1257 {
1258 src.ipv6 = nexthop->src.ipv6;
1259 setsrc = 1;
1260 }
1261 }
c52ef59f
DS
1262 }
1263 continue;
1264 }
7021c425 1265
1266 if ((cmd == RTM_NEWROUTE
1267 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1268 || (cmd == RTM_DELROUTE
1269 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1270 {
fa713d9e 1271 routedesc = recursing ? "recursive, 1 hop" : "single hop";
7021c425 1272
8f7d9fc0 1273 _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf);
fa713d9e 1274 _netlink_route_build_singlepath(routedesc, bytelen,
e8d3d299 1275 nexthop, &req.n, &req.r,
c52ef59f 1276 sizeof req, cmd);
7021c425 1277 nexthop_num++;
1278 break;
1279 }
1280 }
c52ef59f 1281 if (setsrc && (cmd == RTM_NEWROUTE))
0aabccc0
DD
1282 {
1283 if (family == AF_INET)
1284 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
1285 else if (family == AF_INET6)
1286 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen);
1287 }
718e3744 1288 }
1289 else
1290 {
3cadc0cd 1291 char buf[NL_PKT_BUF_SIZE];
718e3744 1292 struct rtattr *rta = (void *) buf;
1293 struct rtnexthop *rtnh;
c52ef59f 1294 union g_addr *src1 = NULL;
718e3744 1295
1296 rta->rta_type = RTA_MULTIPATH;
7021c425 1297 rta->rta_len = RTA_LENGTH (0);
1298 rtnh = RTA_DATA (rta);
718e3744 1299
1300 nexthop_num = 0;
fa713d9e 1301 for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
7021c425 1302 {
37fe7731 1303 if (nexthop_num >= multipath_num)
fa713d9e
CF
1304 break;
1305
1306 if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
c52ef59f
DS
1307 {
1308 /* This only works for IPv4 now */
1309 if (!setsrc)
1310 {
0aabccc0
DD
1311 if (family == AF_INET)
1312 {
1313 if (nexthop->rmap_src.ipv4.s_addr != 0)
1314 {
1315 src.ipv4 = nexthop->rmap_src.ipv4;
1316 setsrc = 1;
1317 }
1318 else if (nexthop->src.ipv4.s_addr != 0)
1319 {
1320 src.ipv4 = nexthop->src.ipv4;
1321 setsrc = 1;
1322 }
1323 }
1324 else if (family == AF_INET6)
1325 {
1326 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6))
1327 {
1328 src.ipv6 = nexthop->rmap_src.ipv6;
1329 setsrc = 1;
1330 }
1331 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6))
1332 {
1333 src.ipv6 = nexthop->src.ipv6;
1334 setsrc = 1;
1335 }
1336 }
c52ef59f
DS
1337 }
1338 continue;
1339 }
fa713d9e 1340
7021c425 1341 if ((cmd == RTM_NEWROUTE
1342 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1343 || (cmd == RTM_DELROUTE
1344 && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))
1345 {
fa713d9e 1346 routedesc = recursing ? "recursive, multihop" : "multihop";
7021c425 1347 nexthop_num++;
1348
fa713d9e 1349 _netlink_route_debug(cmd, p, nexthop,
8f7d9fc0 1350 routedesc, family, zvrf);
fa713d9e 1351 _netlink_route_build_multipath(routedesc, bytelen,
5c610faf 1352 nexthop, rta, rtnh, &req.r, &src1);
7021c425 1353 rtnh = RTNH_NEXT (rtnh);
1354
c52ef59f
DS
1355 if (!setsrc && src1)
1356 {
0aabccc0
DD
1357 if (family == AF_INET)
1358 src.ipv4 = src1->ipv4;
1359 else if (family == AF_INET6)
1360 src.ipv6 = src1->ipv6;
1361
c52ef59f
DS
1362 setsrc = 1;
1363 }
7021c425 1364 }
1365 }
c52ef59f 1366 if (setsrc && (cmd == RTM_NEWROUTE))
0aabccc0
DD
1367 {
1368 if (family == AF_INET)
1369 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen);
1370 else if (family == AF_INET6)
1371 addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen);
82a95360
DS
1372 if (IS_ZEBRA_DEBUG_KERNEL)
1373 zlog_debug("Setting source");
0aabccc0 1374 }
718e3744 1375
1376 if (rta->rta_len > RTA_LENGTH (0))
3cadc0cd 1377 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
7021c425 1378 RTA_PAYLOAD (rta));
718e3744 1379 }
1380
1381 /* If there is no useful nexthop then return. */
1382 if (nexthop_num == 0)
1383 {
1384 if (IS_ZEBRA_DEBUG_KERNEL)
b6178002 1385 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
718e3744 1386 return 0;
1387 }
1388
7021c425 1389skip:
718e3744 1390
1391 /* Destination netlink address. */
1392 memset (&snl, 0, sizeof snl);
1393 snl.nl_family = AF_NETLINK;
1394
718e3744 1395 /* Talk to netlink socket. */
936ebf0a 1396 return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
718e3744 1397}
1398
e3be0432 1399int
1498c059 1400kernel_get_ipmr_sg_stats (void *in)
e3be0432
DS
1401{
1402 int suc = 0;
1403 struct mcast_route_data *mr = (struct mcast_route_data *)in;
1404 struct {
1405 struct nlmsghdr n;
1406 struct ndmsg ndm;
1407 char buf[256];
1408 } req;
1409
1410 mroute = mr;
1411 struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
1412
1413 memset(&req.n, 0, sizeof(req.n));
1414 memset(&req.ndm, 0, sizeof(req.ndm));
1415
1416 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
1417 req.n.nlmsg_flags = NLM_F_REQUEST;
1418 req.ndm.ndm_family = AF_INET;
1419 req.n.nlmsg_type = RTM_GETROUTE;
1420
1421 addattr_l (&req.n, sizeof (req), RTA_IIF, &mroute->ifindex, 4);
1422 addattr_l (&req.n, sizeof (req), RTA_OIF, &mroute->ifindex, 4);
1423 addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4);
1424 addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4);
1425
936ebf0a 1426 suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0);
e3be0432
DS
1427
1428 mroute = NULL;
1429 return suc;
1430}
1431
718e3744 1432int
05737783
CF
1433kernel_route_rib (struct prefix *p, struct prefix *src_p,
1434 struct rib *old, struct rib *new)
718e3744 1435{
be717a0a 1436 if (!old && new)
05737783 1437 return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 0);
be717a0a 1438 if (old && !new)
05737783 1439 return netlink_route_multipath (RTM_DELROUTE, p, src_p, old, 0);
718e3744 1440
05737783 1441 return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 1);
718e3744 1442}
1443
6b8a5694
RW
1444int
1445kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen)
1446{
1447 return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, addr,
1448 lla, llalen);
1449}
718e3744 1450
40c7bdb0 1451/*
1452 * MPLS label forwarding table change via netlink interface.
1453 */
be0dba35 1454int
40c7bdb0 1455netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp)
1456{
1457 mpls_lse_t lse;
1458 zebra_nhlfe_t *nhlfe;
1459 struct nexthop *nexthop = NULL;
37fe7731 1460 unsigned int nexthop_num;
40c7bdb0 1461 const char *routedesc;
1462 struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT);
1463
1464 struct
1465 {
1466 struct nlmsghdr n;
1467 struct rtmsg r;
1468 char buf[NL_PKT_BUF_SIZE];
1469 } req;
1470
1471 memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE);
1472
1473
1474 /*
1475 * Count # nexthops so we can decide whether to use singlepath
1476 * or multipath case.
1477 */
1478 nexthop_num = 0;
1479 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1480 {
1481 nexthop = nhlfe->nexthop;
1482 if (!nexthop)
1483 continue;
1484 if (cmd == RTM_NEWROUTE)
1485 {
1486 /* Count all selected NHLFEs */
1487 if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1488 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
1489 nexthop_num++;
1490 }
1491 else /* DEL */
1492 {
1493 /* Count all installed NHLFEs */
1494 if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
1495 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
1496 nexthop_num++;
1497 }
1498 }
1499
1500 if (nexthop_num == 0) // unexpected
1501 return 0;
1502
1503 req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg));
1504 req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
1505 req.n.nlmsg_type = cmd;
1506 req.r.rtm_family = AF_MPLS;
1507 req.r.rtm_table = RT_TABLE_MAIN;
1508 req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS;
1509 req.r.rtm_protocol = RTPROT_ZEBRA;
1510 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
1511 req.r.rtm_type = RTN_UNICAST;
1512
1513 if (cmd == RTM_NEWROUTE)
1514 /* We do a replace to handle update. */
1515 req.n.nlmsg_flags |= NLM_F_REPLACE;
1516
1517 /* Fill destination */
1518 lse = mpls_lse_encode (lsp->ile.in_label, 0, 0, 1);
1519 addattr_l (&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t));
1520
1521 /* Fill nexthops (paths) based on single-path or multipath. The paths
1522 * chosen depend on the operation.
1523 */
37fe7731 1524 if (nexthop_num == 1 || multipath_num == 1)
40c7bdb0 1525 {
1526 routedesc = "single hop";
1527 _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
1528
1529 nexthop_num = 0;
1530 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1531 {
1532 nexthop = nhlfe->nexthop;
1533 if (!nexthop)
1534 continue;
1535
1536 if ((cmd == RTM_NEWROUTE &&
1537 (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1538 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) ||
1539 (cmd == RTM_DELROUTE &&
1540 (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
1541 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))))
1542 {
1543 /* Add the gateway */
1544 _netlink_mpls_build_singlepath(routedesc, nhlfe,
1545 &req.n, &req.r, sizeof req, cmd);
1546 if (cmd == RTM_NEWROUTE)
1547 {
1548 SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
1549 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1550 }
1551 else
1552 {
1553 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
1554 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1555 }
1556 nexthop_num++;
1557 break;
1558 }
1559 }
1560 }
1561 else /* Multipath case */
1562 {
1563 char buf[NL_PKT_BUF_SIZE];
1564 struct rtattr *rta = (void *) buf;
1565 struct rtnexthop *rtnh;
1566 union g_addr *src1 = NULL;
1567
1568 rta->rta_type = RTA_MULTIPATH;
1569 rta->rta_len = RTA_LENGTH (0);
1570 rtnh = RTA_DATA (rta);
1571
1572 routedesc = "multihop";
1573 _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc);
1574
1575 nexthop_num = 0;
1576 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1577 {
1578 nexthop = nhlfe->nexthop;
1579 if (!nexthop)
1580 continue;
1581
37fe7731 1582 if (nexthop_num >= multipath_num)
40c7bdb0 1583 break;
1584
1585 if ((cmd == RTM_NEWROUTE &&
1586 (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) &&
1587 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) ||
1588 (cmd == RTM_DELROUTE &&
1589 (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) &&
1590 CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))))
1591 {
1592 nexthop_num++;
1593
1594 /* Build the multipath */
1595 _netlink_mpls_build_multipath(routedesc, nhlfe, rta,
1596 rtnh, &req.r, &src1);
1597 rtnh = RTNH_NEXT (rtnh);
1598
1599 if (cmd == RTM_NEWROUTE)
1600 {
1601 SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
1602 SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1603 }
1604 else
1605 {
1606 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
1607 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1608 }
1609
1610 }
1611 }
1612
1613 /* Add the multipath */
1614 if (rta->rta_len > RTA_LENGTH (0))
1615 addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta),
1616 RTA_PAYLOAD (rta));
1617 }
1618
1619 /* Talk to netlink socket. */
936ebf0a 1620 return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0);
40c7bdb0 1621}
1622
1623/*
1624 * Handle failure in LSP install, clear flags for NHLFE.
1625 */
be0dba35 1626void
40c7bdb0 1627clear_nhlfe_installed (zebra_lsp_t *lsp)
1628{
1629 zebra_nhlfe_t *nhlfe;
1630 struct nexthop *nexthop;
1631
1632 for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next)
1633 {
1634 nexthop = nhlfe->nexthop;
1635 if (!nexthop)
1636 continue;
1637
1638 UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED);
1639 UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
1640 }
1641}