1 /* Kernel routing table updates using netlink over GNU/Linux system.
2 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
4 * This file is part of GNU Zebra.
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
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.
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
23 #include <net/if_arp.h>
25 /* Hack for GNU libc version 2. */
27 #define MSG_TRUNC 0x20
28 #endif /* MSG_TRUNC */
34 #include "connected.h"
37 #include "zebra_memory.h"
46 #include "zebra/zserv.h"
47 #include "zebra/zebra_ns.h"
48 #include "zebra/zebra_vrf.h"
50 #include "zebra/redistribute.h"
51 #include "zebra/interface.h"
52 #include "zebra/debug.h"
53 #include "zebra/rtadv.h"
54 #include "zebra/zebra_ptm.h"
55 #include "zebra/zebra_mpls.h"
56 #include "zebra/kernel_netlink.h"
57 #include "zebra/rt_netlink.h"
59 /* TODO - Temporary definitions, need to refine. */
72 #ifndef RTA_ENCAP_TYPE
73 #define RTA_ENCAP_TYPE 21
80 #ifndef LWTUNNEL_ENCAP_MPLS
81 #define LWTUNNEL_ENCAP_MPLS 1
84 #ifndef MPLS_IPTUNNEL_DST
85 #define MPLS_IPTUNNEL_DST 1
87 /* End of temporary definitions */
97 Pending: create an efficient table_id (in a tree/hash) based lookup)
100 vrf_lookup_by_table (u_int32_t table_id
)
103 struct zebra_vrf
*zvrf
;
105 RB_FOREACH (vrf
, vrf_id_head
, &vrfs_by_id
)
107 if ((zvrf
= vrf
->info
) == NULL
||
108 (zvrf
->table_id
!= table_id
))
111 return zvrf_id (zvrf
);
117 /* Looking up routing table by netlink interface. */
119 netlink_routing_table (struct sockaddr_nl
*snl
, struct nlmsghdr
*h
,
124 struct rtattr
*tb
[RTA_MAX
+ 1];
127 vrf_id_t vrf_id
= VRF_DEFAULT
;
129 char anyaddr
[16] = { 0 };
140 rtm
= NLMSG_DATA (h
);
142 if (h
->nlmsg_type
!= RTM_NEWROUTE
)
144 if (rtm
->rtm_type
!= RTN_UNICAST
)
147 len
= h
->nlmsg_len
- NLMSG_LENGTH (sizeof (struct rtmsg
));
151 memset (tb
, 0, sizeof tb
);
152 netlink_parse_rtattr (tb
, RTA_MAX
, RTM_RTA (rtm
), len
);
154 if (rtm
->rtm_flags
& RTM_F_CLONED
)
156 if (rtm
->rtm_protocol
== RTPROT_REDIRECT
)
158 if (rtm
->rtm_protocol
== RTPROT_KERNEL
)
161 if (rtm
->rtm_src_len
!= 0)
164 /* We don't care about change notifications for the MPLS table. */
165 /* TODO: Revisit this. */
166 if (rtm
->rtm_family
== AF_MPLS
)
169 /* Table corresponding to route. */
171 table
= *(int *) RTA_DATA (tb
[RTA_TABLE
]);
173 table
= rtm
->rtm_table
;
176 vrf_id
= vrf_lookup_by_table(table
);
177 if (vrf_id
== VRF_DEFAULT
)
179 if (!is_zebra_valid_kernel_table(table
) &&
180 !is_zebra_main_routing_table(table
))
184 /* Route which inserted by Zebra. */
185 if (rtm
->rtm_protocol
== RTPROT_ZEBRA
)
186 flags
|= ZEBRA_FLAG_SELFROUTE
;
195 index
= *(int *) RTA_DATA (tb
[RTA_OIF
]);
198 dest
= RTA_DATA (tb
[RTA_DST
]);
203 src
= RTA_DATA (tb
[RTA_PREFSRC
]);
206 gate
= RTA_DATA (tb
[RTA_GATEWAY
]);
208 if (tb
[RTA_PRIORITY
])
209 metric
= *(int *) RTA_DATA(tb
[RTA_PRIORITY
]);
213 struct rtattr
*mxrta
[RTAX_MAX
+1];
215 memset (mxrta
, 0, sizeof mxrta
);
216 netlink_parse_rtattr (mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
217 RTA_PAYLOAD(tb
[RTA_METRICS
]));
220 mtu
= *(u_int32_t
*) RTA_DATA(mxrta
[RTAX_MTU
]);
223 if (rtm
->rtm_family
== AF_INET
)
226 memcpy (&p
.u
.prefix4
, dest
, 4);
227 p
.prefixlen
= rtm
->rtm_dst_len
;
229 if (!tb
[RTA_MULTIPATH
])
230 rib_add (AFI_IP
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
,
231 0, flags
, &p
, gate
, src
, index
,
232 table
, metric
, mtu
, 0);
235 /* This is a multipath route */
238 struct rtnexthop
*rtnh
=
239 (struct rtnexthop
*) RTA_DATA (tb
[RTA_MULTIPATH
]);
241 len
= RTA_PAYLOAD (tb
[RTA_MULTIPATH
]);
243 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
244 rib
->type
= ZEBRA_ROUTE_KERNEL
;
247 rib
->metric
= metric
;
249 rib
->vrf_id
= vrf_id
;
251 rib
->nexthop_num
= 0;
252 rib
->uptime
= time (NULL
);
256 if (len
< (int) sizeof (*rtnh
) || rtnh
->rtnh_len
> len
)
259 index
= rtnh
->rtnh_ifindex
;
261 if (rtnh
->rtnh_len
> sizeof (*rtnh
))
263 memset (tb
, 0, sizeof (tb
));
264 netlink_parse_rtattr (tb
, RTA_MAX
, RTNH_DATA (rtnh
),
265 rtnh
->rtnh_len
- sizeof (*rtnh
));
267 gate
= RTA_DATA (tb
[RTA_GATEWAY
]);
273 rib_nexthop_ipv4_ifindex_add (rib
, gate
, src
, index
);
275 rib_nexthop_ipv4_add (rib
, gate
, src
);
278 rib_nexthop_ifindex_add (rib
, index
);
280 len
-= NLMSG_ALIGN(rtnh
->rtnh_len
);
281 rtnh
= RTNH_NEXT(rtnh
);
284 zserv_nexthop_num_warn(__func__
, (const struct prefix
*)&p
,
286 if (rib
->nexthop_num
== 0)
287 XFREE (MTYPE_RIB
, rib
);
289 rib_add_multipath (AFI_IP
, SAFI_UNICAST
, &p
, rib
);
292 if (rtm
->rtm_family
== AF_INET6
)
295 memcpy (&p
.u
.prefix6
, dest
, 16);
296 p
.prefixlen
= rtm
->rtm_dst_len
;
298 rib_add (AFI_IP6
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
,
299 0, flags
, &p
, gate
, src
, index
,
300 table
, metric
, mtu
, 0);
306 /* Routing information change from the kernel. */
308 netlink_route_change (struct sockaddr_nl
*snl
, struct nlmsghdr
*h
,
313 struct rtattr
*tb
[RTA_MAX
+ 1];
314 u_char zebra_flags
= 0;
316 vrf_id_t vrf_id
= VRF_DEFAULT
;
317 char anyaddr
[16] = { 0 };
328 rtm
= NLMSG_DATA (h
);
330 if (!(h
->nlmsg_type
== RTM_NEWROUTE
|| h
->nlmsg_type
== RTM_DELROUTE
))
332 /* If this is not route add/delete message print warning. */
333 zlog_warn ("Kernel message: %d", h
->nlmsg_type
);
337 /* Connected route. */
338 if (IS_ZEBRA_DEBUG_KERNEL
)
339 zlog_debug ("%s %s %s proto %s",
341 RTM_NEWROUTE
? "RTM_NEWROUTE" : "RTM_DELROUTE",
342 rtm
->rtm_family
== AF_INET
? "ipv4" : "ipv6",
343 rtm
->rtm_type
== RTN_UNICAST
? "unicast" : "multicast",
344 nl_rtproto_to_str (rtm
->rtm_protocol
));
346 if (rtm
->rtm_type
!= RTN_UNICAST
)
351 /* We don't care about change notifications for the MPLS table. */
352 /* TODO: Revisit this. */
353 if (rtm
->rtm_family
== AF_MPLS
)
356 len
= h
->nlmsg_len
- NLMSG_LENGTH (sizeof (struct rtmsg
));
360 memset (tb
, 0, sizeof tb
);
361 netlink_parse_rtattr (tb
, RTA_MAX
, RTM_RTA (rtm
), len
);
363 if (rtm
->rtm_flags
& RTM_F_CLONED
)
365 if (rtm
->rtm_protocol
== RTPROT_REDIRECT
)
367 if (rtm
->rtm_protocol
== RTPROT_KERNEL
)
370 if (rtm
->rtm_protocol
== RTPROT_ZEBRA
&& h
->nlmsg_type
== RTM_NEWROUTE
)
372 if (rtm
->rtm_protocol
== RTPROT_ZEBRA
)
373 SET_FLAG(zebra_flags
, ZEBRA_FLAG_SELFROUTE
);
375 if (rtm
->rtm_src_len
!= 0)
377 zlog_warn ("netlink_route_change(): no src len");
381 /* Table corresponding to route. */
383 table
= *(int *) RTA_DATA (tb
[RTA_TABLE
]);
385 table
= rtm
->rtm_table
;
388 vrf_id
= vrf_lookup_by_table(table
);
389 if (vrf_id
== VRF_DEFAULT
)
391 if (!is_zebra_valid_kernel_table(table
) &&
392 !is_zebra_main_routing_table(table
))
403 index
= *(int *) RTA_DATA (tb
[RTA_OIF
]);
406 dest
= RTA_DATA (tb
[RTA_DST
]);
411 gate
= RTA_DATA (tb
[RTA_GATEWAY
]);
414 src
= RTA_DATA (tb
[RTA_PREFSRC
]);
416 if (h
->nlmsg_type
== RTM_NEWROUTE
)
418 if (tb
[RTA_PRIORITY
])
419 metric
= *(int *) RTA_DATA(tb
[RTA_PRIORITY
]);
423 struct rtattr
*mxrta
[RTAX_MAX
+1];
425 memset (mxrta
, 0, sizeof mxrta
);
426 netlink_parse_rtattr (mxrta
, RTAX_MAX
, RTA_DATA(tb
[RTA_METRICS
]),
427 RTA_PAYLOAD(tb
[RTA_METRICS
]));
430 mtu
= *(u_int32_t
*) RTA_DATA(mxrta
[RTAX_MTU
]);
434 if (rtm
->rtm_family
== AF_INET
)
437 memcpy (&p
.u
.prefix4
, dest
, 4);
438 p
.prefixlen
= rtm
->rtm_dst_len
;
440 if (IS_ZEBRA_DEBUG_KERNEL
)
442 char buf
[PREFIX_STRLEN
];
443 zlog_debug ("%s %s vrf %u",
444 h
->nlmsg_type
== RTM_NEWROUTE
? "RTM_NEWROUTE" : "RTM_DELROUTE",
445 prefix2str (&p
, buf
, sizeof(buf
)), vrf_id
);
448 if (h
->nlmsg_type
== RTM_NEWROUTE
)
450 if (!tb
[RTA_MULTIPATH
])
451 rib_add (AFI_IP
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
,
452 0, 0, &p
, gate
, src
, index
,
453 table
, metric
, mtu
, 0);
456 /* This is a multipath route */
459 struct rtnexthop
*rtnh
=
460 (struct rtnexthop
*) RTA_DATA (tb
[RTA_MULTIPATH
]);
462 len
= RTA_PAYLOAD (tb
[RTA_MULTIPATH
]);
464 rib
= XCALLOC (MTYPE_RIB
, sizeof (struct rib
));
465 rib
->type
= ZEBRA_ROUTE_KERNEL
;
468 rib
->metric
= metric
;
470 rib
->vrf_id
= vrf_id
;
472 rib
->nexthop_num
= 0;
473 rib
->uptime
= time (NULL
);
477 if (len
< (int) sizeof (*rtnh
) || rtnh
->rtnh_len
> len
)
480 index
= rtnh
->rtnh_ifindex
;
482 if (rtnh
->rtnh_len
> sizeof (*rtnh
))
484 memset (tb
, 0, sizeof (tb
));
485 netlink_parse_rtattr (tb
, RTA_MAX
, RTNH_DATA (rtnh
),
486 rtnh
->rtnh_len
- sizeof (*rtnh
));
488 gate
= RTA_DATA (tb
[RTA_GATEWAY
]);
494 rib_nexthop_ipv4_ifindex_add (rib
, gate
, src
, index
);
496 rib_nexthop_ipv4_add (rib
, gate
, src
);
499 rib_nexthop_ifindex_add (rib
, index
);
501 len
-= NLMSG_ALIGN(rtnh
->rtnh_len
);
502 rtnh
= RTNH_NEXT(rtnh
);
505 zserv_nexthop_num_warn(__func__
, (const struct prefix
*)&p
,
508 if (rib
->nexthop_num
== 0)
509 XFREE (MTYPE_RIB
, rib
);
511 rib_add_multipath (AFI_IP
, SAFI_UNICAST
, &p
, rib
);
515 rib_delete (AFI_IP
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
, 0, zebra_flags
,
516 &p
, gate
, index
, table
);
519 if (rtm
->rtm_family
== AF_INET6
)
524 memcpy (&p
.u
.prefix6
, dest
, 16);
525 p
.prefixlen
= rtm
->rtm_dst_len
;
527 if (IS_ZEBRA_DEBUG_KERNEL
)
529 char buf
[PREFIX_STRLEN
];
530 zlog_debug ("%s %s vrf %u",
531 h
->nlmsg_type
== RTM_NEWROUTE
? "RTM_NEWROUTE" : "RTM_DELROUTE",
532 prefix2str (&p
, buf
, sizeof(buf
)), vrf_id
);
535 if (h
->nlmsg_type
== RTM_NEWROUTE
)
536 rib_add (AFI_IP6
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
,
537 0, 0, &p
, gate
, src
, index
,
538 table
, metric
, mtu
, 0);
540 rib_delete (AFI_IP6
, SAFI_UNICAST
, vrf_id
, ZEBRA_ROUTE_KERNEL
,
541 0, zebra_flags
, &p
, gate
, index
, table
);
547 /* Routing table read function using netlink interface. Only called
550 netlink_route_read (struct zebra_ns
*zns
)
554 /* Get IPv4 routing table. */
555 ret
= netlink_request (AF_INET
, RTM_GETROUTE
, &zns
->netlink_cmd
);
558 ret
= netlink_parse_info (netlink_routing_table
, &zns
->netlink_cmd
, zns
, 0);
563 /* Get IPv6 routing table. */
564 ret
= netlink_request (AF_INET6
, RTM_GETROUTE
, &zns
->netlink_cmd
);
567 ret
= netlink_parse_info (netlink_routing_table
, &zns
->netlink_cmd
, zns
, 0);
570 #endif /* HAVE_IPV6 */
576 _netlink_route_nl_add_gateway_info (u_char route_family
, u_char gw_family
,
577 struct nlmsghdr
*nlmsg
,
578 size_t req_size
, int bytelen
,
579 struct nexthop
*nexthop
)
581 if (route_family
== AF_MPLS
)
583 struct gw_family_t gw_fam
;
585 gw_fam
.family
= gw_family
;
586 if (gw_family
== AF_INET
)
587 memcpy (&gw_fam
.gate
.ipv4
, &nexthop
->gate
.ipv4
, bytelen
);
589 memcpy (&gw_fam
.gate
.ipv6
, &nexthop
->gate
.ipv6
, bytelen
);
590 addattr_l (nlmsg
, req_size
, RTA_VIA
, &gw_fam
.family
, bytelen
+2);
594 if (gw_family
== AF_INET
)
595 addattr_l (nlmsg
, req_size
, RTA_GATEWAY
, &nexthop
->gate
.ipv4
, bytelen
);
597 addattr_l (nlmsg
, req_size
, RTA_GATEWAY
, &nexthop
->gate
.ipv6
, bytelen
);
602 _netlink_route_rta_add_gateway_info (u_char route_family
, u_char gw_family
,
603 struct rtattr
*rta
, struct rtnexthop
*rtnh
,
604 size_t req_size
, int bytelen
,
605 struct nexthop
*nexthop
)
607 if (route_family
== AF_MPLS
)
609 struct gw_family_t gw_fam
;
611 gw_fam
.family
= gw_family
;
612 if (gw_family
== AF_INET
)
613 memcpy (&gw_fam
.gate
.ipv4
, &nexthop
->gate
.ipv4
, bytelen
);
615 memcpy (&gw_fam
.gate
.ipv6
, &nexthop
->gate
.ipv6
, bytelen
);
616 rta_addattr_l (rta
, req_size
, RTA_VIA
, &gw_fam
.family
, bytelen
+2);
617 rtnh
->rtnh_len
+= RTA_LENGTH (bytelen
+ 2);
621 if (gw_family
== AF_INET
)
622 rta_addattr_l (rta
, req_size
, RTA_GATEWAY
, &nexthop
->gate
.ipv4
, bytelen
);
624 rta_addattr_l (rta
, req_size
, RTA_GATEWAY
, &nexthop
->gate
.ipv6
, bytelen
);
625 rtnh
->rtnh_len
+= sizeof (struct rtattr
) + bytelen
;
629 /* This function takes a nexthop as argument and adds
630 * the appropriate netlink attributes to an existing
633 * @param routedesc: Human readable description of route type
634 * (direct/recursive, single-/multipath)
635 * @param bytelen: Length of addresses in bytes.
636 * @param nexthop: Nexthop information
637 * @param nlmsg: nlmsghdr structure to fill in.
638 * @param req_size: The size allocated for the message.
641 _netlink_route_build_singlepath(
642 const char *routedesc
,
644 struct nexthop
*nexthop
,
645 struct nlmsghdr
*nlmsg
,
650 struct nexthop_label
*nh_label
;
651 mpls_lse_t out_lse
[MPLS_MAX_LABELS
];
654 if (rtmsg
->rtm_family
== AF_INET
&&
655 (nexthop
->type
== NEXTHOP_TYPE_IPV6
656 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
))
658 char buf
[16] = "169.254.0.1";
659 struct in_addr ipv4_ll
;
661 inet_pton (AF_INET
, buf
, &ipv4_ll
);
662 rtmsg
->rtm_flags
|= RTNH_F_ONLINK
;
663 addattr_l (nlmsg
, req_size
, RTA_GATEWAY
, &ipv4_ll
, 4);
664 addattr32 (nlmsg
, req_size
, RTA_OIF
, nexthop
->ifindex
);
666 if (nexthop
->rmap_src
.ipv4
.s_addr
&& (cmd
== RTM_NEWROUTE
))
667 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
668 &nexthop
->rmap_src
.ipv4
, bytelen
);
669 else if (nexthop
->src
.ipv4
.s_addr
&& (cmd
== RTM_NEWROUTE
))
670 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
671 &nexthop
->src
.ipv4
, bytelen
);
673 if (IS_ZEBRA_DEBUG_KERNEL
)
674 zlog_debug(" 5549: _netlink_route_build_singlepath() (%s): "
675 "nexthop via %s if %u",
676 routedesc
, buf
, nexthop
->ifindex
);
681 /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
682 * (in the case of LER)
684 nh_label
= nexthop
->nh_label
;
685 if (rtmsg
->rtm_family
== AF_MPLS
)
688 assert (nh_label
->num_labels
== 1);
691 if (nh_label
&& nh_label
->num_labels
)
693 int i
, num_labels
= 0;
697 for (i
= 0; i
< nh_label
->num_labels
; i
++)
699 if (nh_label
->label
[i
] != MPLS_IMP_NULL_LABEL
)
701 bos
= ((i
== (nh_label
->num_labels
- 1)) ? 1 : 0);
702 out_lse
[i
] = mpls_lse_encode (nh_label
->label
[i
], 0, 0, bos
);
704 sprintf (label_buf
, "label %d", nh_label
->label
[i
]);
707 sprintf (label_buf1
, "/%d", nh_label
->label
[i
]);
708 strcat (label_buf
, label_buf1
);
715 if (rtmsg
->rtm_family
== AF_MPLS
)
716 addattr_l (nlmsg
, req_size
, RTA_NEWDST
,
717 &out_lse
, num_labels
* sizeof(mpls_lse_t
));
721 u_int16_t encap
= LWTUNNEL_ENCAP_MPLS
;
723 addattr_l(nlmsg
, req_size
, RTA_ENCAP_TYPE
,
724 &encap
, sizeof (u_int16_t
));
725 nest
= addattr_nest(nlmsg
, req_size
, RTA_ENCAP
);
726 addattr_l (nlmsg
, req_size
, MPLS_IPTUNNEL_DST
,
727 &out_lse
, num_labels
* sizeof(mpls_lse_t
));
728 addattr_nest_end(nlmsg
, nest
);
733 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ONLINK
))
734 rtmsg
->rtm_flags
|= RTNH_F_ONLINK
;
736 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
737 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
739 _netlink_route_nl_add_gateway_info (rtmsg
->rtm_family
, AF_INET
, nlmsg
,
740 req_size
, bytelen
, nexthop
);
742 if (cmd
== RTM_NEWROUTE
)
744 if (nexthop
->rmap_src
.ipv4
.s_addr
)
745 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
746 &nexthop
->rmap_src
.ipv4
, bytelen
);
747 else if (nexthop
->src
.ipv4
.s_addr
)
748 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
749 &nexthop
->src
.ipv4
, bytelen
);
752 if (IS_ZEBRA_DEBUG_KERNEL
)
753 zlog_debug("netlink_route_multipath() (%s): "
754 "nexthop via %s %s if %u",
756 inet_ntoa (nexthop
->gate
.ipv4
),
757 label_buf
, nexthop
->ifindex
);
759 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
760 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
762 _netlink_route_nl_add_gateway_info (rtmsg
->rtm_family
, AF_INET6
, nlmsg
,
763 req_size
, bytelen
, nexthop
);
765 if (cmd
== RTM_NEWROUTE
)
767 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->rmap_src
.ipv6
))
768 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
769 &nexthop
->rmap_src
.ipv6
, bytelen
);
770 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->src
.ipv6
))
771 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
772 &nexthop
->src
.ipv6
, bytelen
);
775 if (IS_ZEBRA_DEBUG_KERNEL
)
776 zlog_debug("netlink_route_multipath() (%s): "
777 "nexthop via %s %s if %u",
779 inet6_ntoa (nexthop
->gate
.ipv6
),
780 label_buf
, nexthop
->ifindex
);
782 if (nexthop
->type
== NEXTHOP_TYPE_IFINDEX
783 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
785 addattr32 (nlmsg
, req_size
, RTA_OIF
, nexthop
->ifindex
);
787 if (cmd
== RTM_NEWROUTE
)
789 if (nexthop
->rmap_src
.ipv4
.s_addr
)
790 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
791 &nexthop
->rmap_src
.ipv4
, bytelen
);
792 else if (nexthop
->src
.ipv4
.s_addr
)
793 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
794 &nexthop
->src
.ipv4
, bytelen
);
797 if (IS_ZEBRA_DEBUG_KERNEL
)
798 zlog_debug("netlink_route_multipath() (%s): "
799 "nexthop via if %u", routedesc
, nexthop
->ifindex
);
802 if (nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
804 addattr32 (nlmsg
, req_size
, RTA_OIF
, nexthop
->ifindex
);
806 if (cmd
== RTM_NEWROUTE
)
808 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->rmap_src
.ipv6
))
809 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
810 &nexthop
->rmap_src
.ipv6
, bytelen
);
811 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->src
.ipv6
))
812 addattr_l (nlmsg
, req_size
, RTA_PREFSRC
,
813 &nexthop
->src
.ipv6
, bytelen
);
816 if (IS_ZEBRA_DEBUG_KERNEL
)
817 zlog_debug("netlink_route_multipath() (%s): "
818 "nexthop via if %u", routedesc
, nexthop
->ifindex
);
822 /* This function takes a nexthop as argument and
823 * appends to the given rtattr/rtnexthop pair the
824 * representation of the nexthop. If the nexthop
825 * defines a preferred source, the src parameter
826 * will be modified to point to that src, otherwise
827 * it will be kept unmodified.
829 * @param routedesc: Human readable description of route type
830 * (direct/recursive, single-/multipath)
831 * @param bytelen: Length of addresses in bytes.
832 * @param nexthop: Nexthop information
833 * @param rta: rtnetlink attribute structure
834 * @param rtnh: pointer to an rtnetlink nexthop structure
835 * @param src: pointer pointing to a location where
836 * the prefsrc should be stored.
839 _netlink_route_build_multipath(
840 const char *routedesc
,
842 struct nexthop
*nexthop
,
844 struct rtnexthop
*rtnh
,
848 struct nexthop_label
*nh_label
;
849 mpls_lse_t out_lse
[MPLS_MAX_LABELS
];
852 rtnh
->rtnh_len
= sizeof (*rtnh
);
853 rtnh
->rtnh_flags
= 0;
855 rta
->rta_len
+= rtnh
->rtnh_len
;
857 if (rtmsg
->rtm_family
== AF_INET
&&
858 (nexthop
->type
== NEXTHOP_TYPE_IPV6
859 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
))
861 char buf
[16] = "169.254.0.1";
862 struct in_addr ipv4_ll
;
864 inet_pton (AF_INET
, buf
, &ipv4_ll
);
866 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
867 rta_addattr_l (rta
, NL_PKT_BUF_SIZE
, RTA_GATEWAY
,
869 rtnh
->rtnh_len
+= sizeof (struct rtattr
) + bytelen
;
870 rtnh
->rtnh_ifindex
= nexthop
->ifindex
;
872 if (nexthop
->rmap_src
.ipv4
.s_addr
)
873 *src
= &nexthop
->rmap_src
;
874 else if (nexthop
->src
.ipv4
.s_addr
)
875 *src
= &nexthop
->src
;
877 if (IS_ZEBRA_DEBUG_KERNEL
)
878 zlog_debug(" 5549: netlink_route_build_multipath() (%s): "
879 "nexthop via %s if %u",
880 routedesc
, buf
, nexthop
->ifindex
);
885 /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP
886 * (in the case of LER)
888 nh_label
= nexthop
->nh_label
;
889 if (rtmsg
->rtm_family
== AF_MPLS
)
892 assert (nh_label
->num_labels
== 1);
895 if (nh_label
&& nh_label
->num_labels
)
897 int i
, num_labels
= 0;
901 for (i
= 0; i
< nh_label
->num_labels
; i
++)
903 if (nh_label
->label
[i
] != MPLS_IMP_NULL_LABEL
)
905 bos
= ((i
== (nh_label
->num_labels
- 1)) ? 1 : 0);
906 out_lse
[i
] = mpls_lse_encode (nh_label
->label
[i
], 0, 0, bos
);
908 sprintf (label_buf
, "label %d", nh_label
->label
[i
]);
911 sprintf (label_buf1
, "/%d", nh_label
->label
[i
]);
912 strcat (label_buf
, label_buf1
);
919 if (rtmsg
->rtm_family
== AF_MPLS
)
921 rta_addattr_l (rta
, NL_PKT_BUF_SIZE
, RTA_NEWDST
,
922 &out_lse
, num_labels
* sizeof(mpls_lse_t
));
923 rtnh
->rtnh_len
+= RTA_LENGTH (num_labels
* sizeof(mpls_lse_t
));
928 u_int16_t encap
= LWTUNNEL_ENCAP_MPLS
;
929 int len
= rta
->rta_len
;
931 rta_addattr_l(rta
, NL_PKT_BUF_SIZE
, RTA_ENCAP_TYPE
,
932 &encap
, sizeof (u_int16_t
));
933 nest
= rta_nest(rta
, NL_PKT_BUF_SIZE
, RTA_ENCAP
);
934 rta_addattr_l (rta
, NL_PKT_BUF_SIZE
, MPLS_IPTUNNEL_DST
,
935 &out_lse
, num_labels
* sizeof(mpls_lse_t
));
936 rta_nest_end(rta
, nest
);
937 rtnh
->rtnh_len
+= rta
->rta_len
- len
;
942 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ONLINK
))
943 rtnh
->rtnh_flags
|= RTNH_F_ONLINK
;
945 if (nexthop
->type
== NEXTHOP_TYPE_IPV4
946 || nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
)
948 _netlink_route_rta_add_gateway_info (rtmsg
->rtm_family
, AF_INET
, rta
,
949 rtnh
, NL_PKT_BUF_SIZE
, bytelen
, nexthop
);
950 if (nexthop
->rmap_src
.ipv4
.s_addr
)
951 *src
= &nexthop
->rmap_src
;
952 else if (nexthop
->src
.ipv4
.s_addr
)
953 *src
= &nexthop
->src
;
955 if (IS_ZEBRA_DEBUG_KERNEL
)
956 zlog_debug("netlink_route_multipath() (%s): "
957 "nexthop via %s %s if %u",
959 inet_ntoa (nexthop
->gate
.ipv4
),
960 label_buf
, nexthop
->ifindex
);
962 if (nexthop
->type
== NEXTHOP_TYPE_IPV6
963 || nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
965 _netlink_route_rta_add_gateway_info (rtmsg
->rtm_family
, AF_INET6
, rta
,
966 rtnh
, NL_PKT_BUF_SIZE
, bytelen
, nexthop
);
968 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->rmap_src
.ipv6
))
969 *src
= &nexthop
->rmap_src
;
970 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->src
.ipv6
))
971 *src
= &nexthop
->src
;
973 if (IS_ZEBRA_DEBUG_KERNEL
)
974 zlog_debug("netlink_route_multipath() (%s): "
975 "nexthop via %s %s if %u",
977 inet6_ntoa (nexthop
->gate
.ipv6
),
978 label_buf
, nexthop
->ifindex
);
981 if (nexthop
->type
== NEXTHOP_TYPE_IPV4_IFINDEX
982 || nexthop
->type
== NEXTHOP_TYPE_IFINDEX
)
984 rtnh
->rtnh_ifindex
= nexthop
->ifindex
;
986 if (nexthop
->rmap_src
.ipv4
.s_addr
)
987 *src
= &nexthop
->rmap_src
;
988 else if (nexthop
->src
.ipv4
.s_addr
)
989 *src
= &nexthop
->src
;
991 if (IS_ZEBRA_DEBUG_KERNEL
)
992 zlog_debug("netlink_route_multipath() (%s): "
993 "nexthop via if %u", routedesc
, nexthop
->ifindex
);
995 else if (nexthop
->type
== NEXTHOP_TYPE_IPV6_IFINDEX
)
997 rtnh
->rtnh_ifindex
= nexthop
->ifindex
;
999 if (IS_ZEBRA_DEBUG_KERNEL
)
1000 zlog_debug("netlink_route_multipath() (%s): "
1001 "nexthop via if %u", routedesc
, nexthop
->ifindex
);
1005 rtnh
->rtnh_ifindex
= 0;
1010 _netlink_mpls_build_singlepath(
1011 const char *routedesc
,
1012 zebra_nhlfe_t
*nhlfe
,
1013 struct nlmsghdr
*nlmsg
,
1014 struct rtmsg
*rtmsg
,
1021 family
= NHLFE_FAMILY (nhlfe
);
1022 bytelen
= (family
== AF_INET
? 4 : 16);
1023 _netlink_route_build_singlepath(routedesc
, bytelen
, nhlfe
->nexthop
,
1024 nlmsg
, rtmsg
, req_size
, cmd
);
1029 _netlink_mpls_build_multipath(
1030 const char *routedesc
,
1031 zebra_nhlfe_t
*nhlfe
,
1033 struct rtnexthop
*rtnh
,
1034 struct rtmsg
*rtmsg
,
1040 family
= NHLFE_FAMILY (nhlfe
);
1041 bytelen
= (family
== AF_INET
? 4 : 16);
1042 _netlink_route_build_multipath(routedesc
, bytelen
, nhlfe
->nexthop
,
1043 rta
, rtnh
, rtmsg
, src
);
1047 /* Log debug information for netlink_route_multipath
1048 * if debug logging is enabled.
1050 * @param cmd: Netlink command which is to be processed
1051 * @param p: Prefix for which the change is due
1052 * @param nexthop: Nexthop which is currently processed
1053 * @param routedesc: Semantic annotation for nexthop
1054 * (recursive, multipath, etc.)
1055 * @param family: Address family which the change concerns
1058 _netlink_route_debug(
1061 struct nexthop
*nexthop
,
1062 const char *routedesc
,
1064 struct zebra_vrf
*zvrf
)
1066 if (IS_ZEBRA_DEBUG_KERNEL
)
1068 char buf
[PREFIX_STRLEN
];
1069 zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s",
1071 nl_msg_type_to_str (cmd
),
1072 prefix2str (p
, buf
, sizeof(buf
)), zvrf_id (zvrf
),
1073 (nexthop
) ? nexthop_type_to_str (nexthop
->type
) : "UNK");
1078 _netlink_mpls_debug(
1081 const char *routedesc
)
1083 if (IS_ZEBRA_DEBUG_KERNEL
)
1084 zlog_debug ("netlink_mpls_multipath() (%s): %s %u/20",
1085 routedesc
, nl_msg_type_to_str (cmd
), label
);
1089 netlink_neigh_update (int cmd
, int ifindex
, uint32_t addr
, char *lla
, int llalen
)
1097 struct zebra_ns
*zns
= zebra_ns_lookup (NS_DEFAULT
);
1099 memset(&req
.n
, 0, sizeof(req
.n
));
1100 memset(&req
.ndm
, 0, sizeof(req
.ndm
));
1102 req
.n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ndmsg
));
1103 req
.n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
1104 req
.n
.nlmsg_type
= cmd
; //RTM_NEWNEIGH or RTM_DELNEIGH
1105 req
.ndm
.ndm_family
= AF_INET
;
1106 req
.ndm
.ndm_state
= NUD_PERMANENT
;
1107 req
.ndm
.ndm_ifindex
= ifindex
;
1108 req
.ndm
.ndm_type
= RTN_UNICAST
;
1110 addattr_l(&req
.n
, sizeof(req
), NDA_DST
, &addr
, 4);
1111 addattr_l(&req
.n
, sizeof(req
), NDA_LLADDR
, lla
, llalen
);
1113 return netlink_talk (&req
.n
, &zns
->netlink_cmd
, zns
);
1116 /* Routing table change via netlink interface. */
1117 /* Update flag indicates whether this is a "replace" or not. */
1119 netlink_route_multipath (int cmd
, struct prefix
*p
, struct rib
*rib
,
1123 struct sockaddr_nl snl
;
1124 struct nexthop
*nexthop
= NULL
, *tnexthop
;
1128 int family
= PREFIX_FAMILY(p
);
1129 const char *routedesc
;
1137 char buf
[NL_PKT_BUF_SIZE
];
1140 struct zebra_ns
*zns
= zebra_ns_lookup (NS_DEFAULT
);
1141 struct zebra_vrf
*zvrf
= vrf_info_lookup (rib
->vrf_id
);
1143 memset (&req
, 0, sizeof req
- NL_PKT_BUF_SIZE
);
1145 bytelen
= (family
== AF_INET
? 4 : 16);
1147 req
.n
.nlmsg_len
= NLMSG_LENGTH (sizeof (struct rtmsg
));
1148 req
.n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
1149 if ((cmd
== RTM_NEWROUTE
) && update
)
1150 req
.n
.nlmsg_flags
|= NLM_F_REPLACE
;
1151 req
.n
.nlmsg_type
= cmd
;
1152 req
.r
.rtm_family
= family
;
1153 req
.r
.rtm_dst_len
= p
->prefixlen
;
1154 req
.r
.rtm_protocol
= RTPROT_ZEBRA
;
1155 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
1157 if ((rib
->flags
& ZEBRA_FLAG_BLACKHOLE
) || (rib
->flags
& ZEBRA_FLAG_REJECT
))
1162 if (cmd
== RTM_NEWROUTE
)
1166 if (rib
->flags
& ZEBRA_FLAG_BLACKHOLE
)
1167 req
.r
.rtm_type
= RTN_BLACKHOLE
;
1168 else if (rib
->flags
& ZEBRA_FLAG_REJECT
)
1169 req
.r
.rtm_type
= RTN_UNREACHABLE
;
1171 assert (RTN_BLACKHOLE
!= RTN_UNREACHABLE
); /* false */
1174 req
.r
.rtm_type
= RTN_UNICAST
;
1177 addattr_l (&req
.n
, sizeof req
, RTA_DST
, &p
->u
.prefix
, bytelen
);
1180 /* Hardcode the metric for all routes coming from zebra. Metric isn't used
1181 * either by the kernel or by zebra. Its purely for calculating best path(s)
1182 * by the routing protocol and for communicating with protocol peers.
1184 addattr32 (&req
.n
, sizeof req
, RTA_PRIORITY
, NL_DEFAULT_ROUTE_METRIC
);
1186 /* Table corresponding to this route. */
1187 if (rib
->table
< 256)
1188 req
.r
.rtm_table
= rib
->table
;
1191 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
1192 addattr32(&req
.n
, sizeof req
, RTA_TABLE
, rib
->table
);
1195 if (rib
->mtu
|| rib
->nexthop_mtu
)
1197 char buf
[NL_PKT_BUF_SIZE
];
1198 struct rtattr
*rta
= (void *) buf
;
1199 u_int32_t mtu
= rib
->mtu
;
1200 if (!mtu
|| (rib
->nexthop_mtu
&& rib
->nexthop_mtu
< mtu
))
1201 mtu
= rib
->nexthop_mtu
;
1202 rta
->rta_type
= RTA_METRICS
;
1203 rta
->rta_len
= RTA_LENGTH(0);
1204 rta_addattr_l (rta
, NL_PKT_BUF_SIZE
, RTAX_MTU
, &mtu
, sizeof mtu
);
1205 addattr_l (&req
.n
, NL_PKT_BUF_SIZE
, RTA_METRICS
, RTA_DATA (rta
),
1211 if (cmd
== RTM_NEWROUTE
)
1212 for (ALL_NEXTHOPS_RO(rib
->nexthop
, nexthop
, tnexthop
, recursing
))
1214 /* We shouldn't encounter recursive nexthops on discard routes,
1215 * but it is probably better to handle that case correctly anyway.
1217 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1223 /* Count overall nexthops so we can decide whether to use singlepath
1224 * or multipath case. */
1226 for (ALL_NEXTHOPS_RO(rib
->nexthop
, nexthop
, tnexthop
, recursing
))
1228 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1230 if (cmd
== RTM_NEWROUTE
&& !CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
1232 if (cmd
== RTM_DELROUTE
&& !CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
1238 /* Singlepath case. */
1239 if (nexthop_num
== 1 || MULTIPATH_NUM
== 1)
1242 for (ALL_NEXTHOPS_RO(rib
->nexthop
, nexthop
, tnexthop
, recursing
))
1244 if (CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1248 if (family
== AF_INET
)
1250 if (nexthop
->rmap_src
.ipv4
.s_addr
!= 0)
1252 src
.ipv4
= nexthop
->rmap_src
.ipv4
;
1255 else if (nexthop
->src
.ipv4
.s_addr
!= 0)
1257 src
.ipv4
= nexthop
->src
.ipv4
;
1261 else if (family
== AF_INET6
)
1263 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->rmap_src
.ipv6
))
1265 src
.ipv6
= nexthop
->rmap_src
.ipv6
;
1268 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->src
.ipv6
))
1270 src
.ipv6
= nexthop
->src
.ipv6
;
1278 if ((cmd
== RTM_NEWROUTE
1279 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
1280 || (cmd
== RTM_DELROUTE
1281 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)))
1283 routedesc
= recursing
? "recursive, 1 hop" : "single hop";
1285 _netlink_route_debug(cmd
, p
, nexthop
, routedesc
, family
, zvrf
);
1286 _netlink_route_build_singlepath(routedesc
, bytelen
,
1287 nexthop
, &req
.n
, &req
.r
,
1293 if (setsrc
&& (cmd
== RTM_NEWROUTE
))
1295 if (family
== AF_INET
)
1296 addattr_l (&req
.n
, sizeof req
, RTA_PREFSRC
, &src
.ipv4
, bytelen
);
1297 else if (family
== AF_INET6
)
1298 addattr_l (&req
.n
, sizeof req
, RTA_PREFSRC
, &src
.ipv6
, bytelen
);
1303 char buf
[NL_PKT_BUF_SIZE
];
1304 struct rtattr
*rta
= (void *) buf
;
1305 struct rtnexthop
*rtnh
;
1306 union g_addr
*src1
= NULL
;
1308 rta
->rta_type
= RTA_MULTIPATH
;
1309 rta
->rta_len
= RTA_LENGTH (0);
1310 rtnh
= RTA_DATA (rta
);
1313 for (ALL_NEXTHOPS_RO(rib
->nexthop
, nexthop
, tnexthop
, recursing
))
1315 if (nexthop_num
>= MULTIPATH_NUM
)
1318 if (CHECK_FLAG(nexthop
->flags
, NEXTHOP_FLAG_RECURSIVE
))
1320 /* This only works for IPv4 now */
1323 if (family
== AF_INET
)
1325 if (nexthop
->rmap_src
.ipv4
.s_addr
!= 0)
1327 src
.ipv4
= nexthop
->rmap_src
.ipv4
;
1330 else if (nexthop
->src
.ipv4
.s_addr
!= 0)
1332 src
.ipv4
= nexthop
->src
.ipv4
;
1336 else if (family
== AF_INET6
)
1338 if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->rmap_src
.ipv6
))
1340 src
.ipv6
= nexthop
->rmap_src
.ipv6
;
1343 else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop
->src
.ipv6
))
1345 src
.ipv6
= nexthop
->src
.ipv6
;
1353 if ((cmd
== RTM_NEWROUTE
1354 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
1355 || (cmd
== RTM_DELROUTE
1356 && CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
)))
1358 routedesc
= recursing
? "recursive, multihop" : "multihop";
1361 _netlink_route_debug(cmd
, p
, nexthop
,
1362 routedesc
, family
, zvrf
);
1363 _netlink_route_build_multipath(routedesc
, bytelen
,
1364 nexthop
, rta
, rtnh
, &req
.r
, &src1
);
1365 rtnh
= RTNH_NEXT (rtnh
);
1367 if (!setsrc
&& src1
)
1369 if (family
== AF_INET
)
1370 src
.ipv4
= src1
->ipv4
;
1371 else if (family
== AF_INET6
)
1372 src
.ipv6
= src1
->ipv6
;
1378 if (setsrc
&& (cmd
== RTM_NEWROUTE
))
1380 if (family
== AF_INET
)
1381 addattr_l (&req
.n
, sizeof req
, RTA_PREFSRC
, &src
.ipv4
, bytelen
);
1382 else if (family
== AF_INET6
)
1383 addattr_l (&req
.n
, sizeof req
, RTA_PREFSRC
, &src
.ipv6
, bytelen
);
1384 if (IS_ZEBRA_DEBUG_KERNEL
)
1385 zlog_debug("Setting source");
1388 if (rta
->rta_len
> RTA_LENGTH (0))
1389 addattr_l (&req
.n
, NL_PKT_BUF_SIZE
, RTA_MULTIPATH
, RTA_DATA (rta
),
1393 /* If there is no useful nexthop then return. */
1394 if (nexthop_num
== 0)
1396 if (IS_ZEBRA_DEBUG_KERNEL
)
1397 zlog_debug ("netlink_route_multipath(): No useful nexthop.");
1403 /* Destination netlink address. */
1404 memset (&snl
, 0, sizeof snl
);
1405 snl
.nl_family
= AF_NETLINK
;
1407 /* Talk to netlink socket. */
1408 return netlink_talk (&req
.n
, &zns
->netlink_cmd
, zns
);
1412 kernel_route_rib (struct prefix
*p
, struct rib
*old
, struct rib
*new)
1415 return netlink_route_multipath (RTM_NEWROUTE
, p
, new, 0);
1417 return netlink_route_multipath (RTM_DELROUTE
, p
, old
, 0);
1419 return netlink_route_multipath (RTM_NEWROUTE
, p
, new, 1);
1423 kernel_neigh_update (int add
, int ifindex
, uint32_t addr
, char *lla
, int llalen
)
1425 return netlink_neigh_update(add
? RTM_NEWNEIGH
: RTM_DELNEIGH
, ifindex
, addr
,
1430 * MPLS label forwarding table change via netlink interface.
1433 netlink_mpls_multipath (int cmd
, zebra_lsp_t
*lsp
)
1436 zebra_nhlfe_t
*nhlfe
;
1437 struct nexthop
*nexthop
= NULL
;
1439 const char *routedesc
;
1440 struct zebra_ns
*zns
= zebra_ns_lookup (NS_DEFAULT
);
1446 char buf
[NL_PKT_BUF_SIZE
];
1449 memset (&req
, 0, sizeof req
- NL_PKT_BUF_SIZE
);
1453 * Count # nexthops so we can decide whether to use singlepath
1454 * or multipath case.
1457 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1459 nexthop
= nhlfe
->nexthop
;
1462 if (cmd
== RTM_NEWROUTE
)
1464 /* Count all selected NHLFEs */
1465 if (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_SELECTED
) &&
1466 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))
1471 /* Count all installed NHLFEs */
1472 if (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) &&
1473 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))
1478 if (nexthop_num
== 0) // unexpected
1481 req
.n
.nlmsg_len
= NLMSG_LENGTH (sizeof (struct rtmsg
));
1482 req
.n
.nlmsg_flags
= NLM_F_CREATE
| NLM_F_REQUEST
;
1483 req
.n
.nlmsg_type
= cmd
;
1484 req
.r
.rtm_family
= AF_MPLS
;
1485 req
.r
.rtm_table
= RT_TABLE_MAIN
;
1486 req
.r
.rtm_dst_len
= MPLS_LABEL_LEN_BITS
;
1487 req
.r
.rtm_protocol
= RTPROT_ZEBRA
;
1488 req
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
1489 req
.r
.rtm_type
= RTN_UNICAST
;
1491 if (cmd
== RTM_NEWROUTE
)
1492 /* We do a replace to handle update. */
1493 req
.n
.nlmsg_flags
|= NLM_F_REPLACE
;
1495 /* Fill destination */
1496 lse
= mpls_lse_encode (lsp
->ile
.in_label
, 0, 0, 1);
1497 addattr_l (&req
.n
, sizeof req
, RTA_DST
, &lse
, sizeof(mpls_lse_t
));
1499 /* Fill nexthops (paths) based on single-path or multipath. The paths
1500 * chosen depend on the operation.
1502 if (nexthop_num
== 1 || MULTIPATH_NUM
== 1)
1504 routedesc
= "single hop";
1505 _netlink_mpls_debug(cmd
, lsp
->ile
.in_label
, routedesc
);
1508 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1510 nexthop
= nhlfe
->nexthop
;
1514 if ((cmd
== RTM_NEWROUTE
&&
1515 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_SELECTED
) &&
1516 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))) ||
1517 (cmd
== RTM_DELROUTE
&&
1518 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) &&
1519 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))))
1521 /* Add the gateway */
1522 _netlink_mpls_build_singlepath(routedesc
, nhlfe
,
1523 &req
.n
, &req
.r
, sizeof req
, cmd
);
1524 if (cmd
== RTM_NEWROUTE
)
1526 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1527 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
1531 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1532 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
1539 else /* Multipath case */
1541 char buf
[NL_PKT_BUF_SIZE
];
1542 struct rtattr
*rta
= (void *) buf
;
1543 struct rtnexthop
*rtnh
;
1544 union g_addr
*src1
= NULL
;
1546 rta
->rta_type
= RTA_MULTIPATH
;
1547 rta
->rta_len
= RTA_LENGTH (0);
1548 rtnh
= RTA_DATA (rta
);
1550 routedesc
= "multihop";
1551 _netlink_mpls_debug(cmd
, lsp
->ile
.in_label
, routedesc
);
1554 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1556 nexthop
= nhlfe
->nexthop
;
1560 if (MULTIPATH_NUM
!= 0 && nexthop_num
>= MULTIPATH_NUM
)
1563 if ((cmd
== RTM_NEWROUTE
&&
1564 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_SELECTED
) &&
1565 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_ACTIVE
))) ||
1566 (cmd
== RTM_DELROUTE
&&
1567 (CHECK_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
) &&
1568 CHECK_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
))))
1572 /* Build the multipath */
1573 _netlink_mpls_build_multipath(routedesc
, nhlfe
, rta
,
1574 rtnh
, &req
.r
, &src1
);
1575 rtnh
= RTNH_NEXT (rtnh
);
1577 if (cmd
== RTM_NEWROUTE
)
1579 SET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1580 SET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
1584 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1585 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);
1591 /* Add the multipath */
1592 if (rta
->rta_len
> RTA_LENGTH (0))
1593 addattr_l (&req
.n
, NL_PKT_BUF_SIZE
, RTA_MULTIPATH
, RTA_DATA (rta
),
1597 /* Talk to netlink socket. */
1598 return netlink_talk (&req
.n
, &zns
->netlink_cmd
, zns
);
1602 * Handle failure in LSP install, clear flags for NHLFE.
1605 clear_nhlfe_installed (zebra_lsp_t
*lsp
)
1607 zebra_nhlfe_t
*nhlfe
;
1608 struct nexthop
*nexthop
;
1610 for (nhlfe
= lsp
->nhlfe_list
; nhlfe
; nhlfe
= nhlfe
->next
)
1612 nexthop
= nhlfe
->nexthop
;
1616 UNSET_FLAG (nhlfe
->flags
, NHLFE_FLAG_INSTALLED
);
1617 UNSET_FLAG (nexthop
->flags
, NEXTHOP_FLAG_FIB
);