diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 2779 |
1 files changed, 1378 insertions, 1401 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index a544593dd6..80c7c09229 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -96,517 +96,507 @@ #endif /* End of temporary definitions */ -struct gw_family_t -{ - u_int16_t filler; - u_int16_t family; - union g_addr gate; +struct gw_family_t { + u_int16_t filler; + u_int16_t family; + union g_addr gate; }; /* Pending: create an efficient table_id (in a tree/hash) based lookup) */ -static vrf_id_t -vrf_lookup_by_table (u_int32_t table_id) +static vrf_id_t vrf_lookup_by_table(u_int32_t table_id) { - struct vrf *vrf; - struct zebra_vrf *zvrf; + struct vrf *vrf; + struct zebra_vrf *zvrf; - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) - { - if ((zvrf = vrf->info) == NULL || - (zvrf->table_id != table_id)) - continue; + RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id) + { + if ((zvrf = vrf->info) == NULL || (zvrf->table_id != table_id)) + continue; - return zvrf_id (zvrf); - } + return zvrf_id(zvrf); + } - return VRF_DEFAULT; + return VRF_DEFAULT; } /* Looking up routing table by netlink interface. */ -static int -netlink_route_change_read_unicast (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id, int startup) +static int netlink_route_change_read_unicast(struct sockaddr_nl *snl, + struct nlmsghdr *h, ns_id_t ns_id, + int startup) { - int len; - struct rtmsg *rtm; - struct rtattr *tb[RTA_MAX + 1]; - u_char flags = 0; - struct prefix p; - struct prefix_ipv6 src_p; - vrf_id_t vrf_id = VRF_DEFAULT; - - char anyaddr[16] = { 0 }; - - int index = 0; - int table; - int metric = 0; - u_int32_t mtu = 0; - - void *dest = NULL; - void *gate = NULL; - void *prefsrc = NULL; /* IPv4 preferred source host address */ - void *src = NULL; /* IPv6 srcdest source prefix */ - - rtm = NLMSG_DATA (h); - - if (startup && h->nlmsg_type != RTM_NEWROUTE) - return 0; - if (startup && rtm->rtm_type != RTN_UNICAST) - return 0; - - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); - if (len < 0) - return -1; - - memset (tb, 0, sizeof tb); - netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); - - if (rtm->rtm_flags & RTM_F_CLONED) - return 0; - if (rtm->rtm_protocol == RTPROT_REDIRECT) - return 0; - if (rtm->rtm_protocol == RTPROT_KERNEL) - return 0; - - if (!startup && - rtm->rtm_protocol == RTPROT_ZEBRA && - h->nlmsg_type == RTM_NEWROUTE) - return 0; - - /* We don't care about change notifications for the MPLS table. */ - /* TODO: Revisit this. */ - if (rtm->rtm_family == AF_MPLS) - return 0; - - /* Table corresponding to route. */ - if (tb[RTA_TABLE]) - table = *(int *) RTA_DATA (tb[RTA_TABLE]); - else - table = rtm->rtm_table; - - /* Map to VRF */ - vrf_id = vrf_lookup_by_table(table); - if (vrf_id == VRF_DEFAULT) - { - if (!is_zebra_valid_kernel_table(table) && - !is_zebra_main_routing_table(table)) - return 0; - } - - /* Route which inserted by Zebra. */ - if (rtm->rtm_protocol == RTPROT_ZEBRA) - flags |= ZEBRA_FLAG_SELFROUTE; - - if (tb[RTA_OIF]) - index = *(int *) RTA_DATA (tb[RTA_OIF]); - - if (tb[RTA_DST]) - dest = RTA_DATA (tb[RTA_DST]); - else - dest = anyaddr; - - if (tb[RTA_SRC]) - src = RTA_DATA (tb[RTA_SRC]); - else - src = anyaddr; - - if (tb[RTA_PREFSRC]) - prefsrc = RTA_DATA (tb[RTA_PREFSRC]); - - if (tb[RTA_GATEWAY]) - gate = RTA_DATA (tb[RTA_GATEWAY]); - - if (h->nlmsg_type == RTM_NEWROUTE) - { - if (tb[RTA_PRIORITY]) - metric = *(int *) RTA_DATA(tb[RTA_PRIORITY]); - - if (tb[RTA_METRICS]) - { - struct rtattr *mxrta[RTAX_MAX+1]; - - memset (mxrta, 0, sizeof mxrta); - netlink_parse_rtattr (mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), - RTA_PAYLOAD(tb[RTA_METRICS])); - - if (mxrta[RTAX_MTU]) - mtu = *(u_int32_t *) RTA_DATA(mxrta[RTAX_MTU]); - } - } - - if (rtm->rtm_family == AF_INET) - { - p.family = AF_INET; - memcpy (&p.u.prefix4, dest, 4); - p.prefixlen = rtm->rtm_dst_len; - } - else if (rtm->rtm_family == AF_INET6) - { - p.family = AF_INET6; - memcpy (&p.u.prefix6, dest, 16); - p.prefixlen = rtm->rtm_dst_len; - - src_p.family = AF_INET6; - memcpy (&src_p.prefix, src, 16); - src_p.prefixlen = rtm->rtm_src_len; - } - - if (rtm->rtm_src_len != 0) - { - char buf[PREFIX_STRLEN]; - zlog_warn ("unsupported IPv[4|6] sourcedest route (dest %s vrf %u)", - prefix2str (&p, buf, sizeof(buf)), vrf_id); - return 0; - } - - if (IS_ZEBRA_DEBUG_KERNEL) - { - char buf[PREFIX_STRLEN]; - char buf2[PREFIX_STRLEN]; - zlog_debug ("%s %s%s%s vrf %u", - nl_msg_type_to_str (h->nlmsg_type), - prefix2str (&p, buf, sizeof(buf)), - src_p.prefixlen ? " from " : "", - src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) : "", - vrf_id); - } - - afi_t afi = AFI_IP; - if (rtm->rtm_family == AF_INET6) - afi = AFI_IP6; - - if (h->nlmsg_type == RTM_NEWROUTE) - { - if (!tb[RTA_MULTIPATH]) - rib_add (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, - 0, flags, &p, NULL, gate, prefsrc, index, - table, metric, mtu, 0); - else - { - /* This is a multipath route */ - - struct rib *rib; - struct rtnexthop *rtnh = - (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); - - len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); - - rib = XCALLOC (MTYPE_RIB, sizeof (struct rib)); - rib->type = ZEBRA_ROUTE_KERNEL; - rib->distance = 0; - rib->flags = flags; - rib->metric = metric; - rib->mtu = mtu; - rib->vrf_id = vrf_id; - rib->table = table; - rib->nexthop_num = 0; - rib->uptime = time (NULL); - - for (;;) - { - if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) - break; - - index = rtnh->rtnh_ifindex; - gate = 0; - if (rtnh->rtnh_len > sizeof (*rtnh)) - { - memset (tb, 0, sizeof (tb)); - netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), - rtnh->rtnh_len - sizeof (*rtnh)); - if (tb[RTA_GATEWAY]) - gate = RTA_DATA (tb[RTA_GATEWAY]); - } - - if (gate) - { - if (rtm->rtm_family == AF_INET) - { - if (index) - rib_nexthop_ipv4_ifindex_add (rib, gate, prefsrc, index); - else - rib_nexthop_ipv4_add (rib, gate, prefsrc); - } - else if (rtm->rtm_family == AF_INET6) - { - if (index) - rib_nexthop_ipv6_ifindex_add (rib, gate, index); - else - rib_nexthop_ipv6_add (rib,gate); - } - } - else - rib_nexthop_ifindex_add (rib, index); - - len -= NLMSG_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } - - zserv_nexthop_num_warn(__func__, (const struct prefix *)&p, - rib->nexthop_num); - if (rib->nexthop_num == 0) - XFREE (MTYPE_RIB, rib); - else - rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, rib); - } - } - else - { - if (!tb[RTA_MULTIPATH]) - rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags, - &p, NULL, gate, index, table); - else - { - struct rtnexthop *rtnh = - (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); - - len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); - - for (;;) - { - if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) - break; - - gate = NULL; - if (rtnh->rtnh_len > sizeof (*rtnh)) - { - memset (tb, 0, sizeof (tb)); - netlink_parse_rtattr (tb, RTA_MAX, RTNH_DATA (rtnh), - rtnh->rtnh_len - sizeof (*rtnh)); - if (tb[RTA_GATEWAY]) - gate = RTA_DATA (tb[RTA_GATEWAY]); - } - - if (gate) - rib_delete (afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, 0, flags, - &p, NULL, gate, index, table); - - len -= NLMSG_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } - } - } - - return 0; + int len; + struct rtmsg *rtm; + struct rtattr *tb[RTA_MAX + 1]; + u_char flags = 0; + struct prefix p; + struct prefix_ipv6 src_p; + vrf_id_t vrf_id = VRF_DEFAULT; + + char anyaddr[16] = {0}; + + int index = 0; + int table; + int metric = 0; + u_int32_t mtu = 0; + + void *dest = NULL; + void *gate = NULL; + void *prefsrc = NULL; /* IPv4 preferred source host address */ + void *src = NULL; /* IPv6 srcdest source prefix */ + + rtm = NLMSG_DATA(h); + + if (startup && h->nlmsg_type != RTM_NEWROUTE) + return 0; + if (startup && rtm->rtm_type != RTN_UNICAST) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + if (len < 0) + return -1; + + memset(tb, 0, sizeof tb); + netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); + + if (rtm->rtm_flags & RTM_F_CLONED) + return 0; + if (rtm->rtm_protocol == RTPROT_REDIRECT) + return 0; + if (rtm->rtm_protocol == RTPROT_KERNEL) + return 0; + + if (!startup && rtm->rtm_protocol == RTPROT_ZEBRA + && h->nlmsg_type == RTM_NEWROUTE) + return 0; + + /* We don't care about change notifications for the MPLS table. */ + /* TODO: Revisit this. */ + if (rtm->rtm_family == AF_MPLS) + return 0; + + /* Table corresponding to route. */ + if (tb[RTA_TABLE]) + table = *(int *)RTA_DATA(tb[RTA_TABLE]); + else + table = rtm->rtm_table; + + /* Map to VRF */ + vrf_id = vrf_lookup_by_table(table); + if (vrf_id == VRF_DEFAULT) { + if (!is_zebra_valid_kernel_table(table) + && !is_zebra_main_routing_table(table)) + return 0; + } + + /* Route which inserted by Zebra. */ + if (rtm->rtm_protocol == RTPROT_ZEBRA) + flags |= ZEBRA_FLAG_SELFROUTE; + + if (tb[RTA_OIF]) + index = *(int *)RTA_DATA(tb[RTA_OIF]); + + if (tb[RTA_DST]) + dest = RTA_DATA(tb[RTA_DST]); + else + dest = anyaddr; + + if (tb[RTA_SRC]) + src = RTA_DATA(tb[RTA_SRC]); + else + src = anyaddr; + + if (tb[RTA_PREFSRC]) + prefsrc = RTA_DATA(tb[RTA_PREFSRC]); + + if (tb[RTA_GATEWAY]) + gate = RTA_DATA(tb[RTA_GATEWAY]); + + if (h->nlmsg_type == RTM_NEWROUTE) { + if (tb[RTA_PRIORITY]) + metric = *(int *)RTA_DATA(tb[RTA_PRIORITY]); + + if (tb[RTA_METRICS]) { + struct rtattr *mxrta[RTAX_MAX + 1]; + + memset(mxrta, 0, sizeof mxrta); + netlink_parse_rtattr(mxrta, RTAX_MAX, + RTA_DATA(tb[RTA_METRICS]), + RTA_PAYLOAD(tb[RTA_METRICS])); + + if (mxrta[RTAX_MTU]) + mtu = *(u_int32_t *)RTA_DATA(mxrta[RTAX_MTU]); + } + } + + if (rtm->rtm_family == AF_INET) { + p.family = AF_INET; + memcpy(&p.u.prefix4, dest, 4); + p.prefixlen = rtm->rtm_dst_len; + } else if (rtm->rtm_family == AF_INET6) { + p.family = AF_INET6; + memcpy(&p.u.prefix6, dest, 16); + p.prefixlen = rtm->rtm_dst_len; + + src_p.family = AF_INET6; + memcpy(&src_p.prefix, src, 16); + src_p.prefixlen = rtm->rtm_src_len; + } + + if (rtm->rtm_src_len != 0) { + char buf[PREFIX_STRLEN]; + zlog_warn( + "unsupported IPv[4|6] sourcedest route (dest %s vrf %u)", + prefix2str(&p, buf, sizeof(buf)), vrf_id); + return 0; + } + + if (IS_ZEBRA_DEBUG_KERNEL) { + char buf[PREFIX_STRLEN]; + char buf2[PREFIX_STRLEN]; + zlog_debug( + "%s %s%s%s vrf %u", nl_msg_type_to_str(h->nlmsg_type), + prefix2str(&p, buf, sizeof(buf)), + src_p.prefixlen ? " from " : "", + src_p.prefixlen ? prefix2str(&src_p, buf2, sizeof(buf2)) + : "", + vrf_id); + } + + afi_t afi = AFI_IP; + if (rtm->rtm_family == AF_INET6) + afi = AFI_IP6; + + if (h->nlmsg_type == RTM_NEWROUTE) { + if (!tb[RTA_MULTIPATH]) + rib_add(afi, SAFI_UNICAST, vrf_id, ZEBRA_ROUTE_KERNEL, + 0, flags, &p, NULL, gate, prefsrc, index, table, + metric, mtu, 0); + else { + /* This is a multipath route */ + + struct rib *rib; + struct rtnexthop *rtnh = + (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); + + rib = XCALLOC(MTYPE_RIB, sizeof(struct rib)); + rib->type = ZEBRA_ROUTE_KERNEL; + rib->distance = 0; + rib->flags = flags; + rib->metric = metric; + rib->mtu = mtu; + rib->vrf_id = vrf_id; + rib->table = table; + rib->nexthop_num = 0; + rib->uptime = time(NULL); + + for (;;) { + if (len < (int)sizeof(*rtnh) + || rtnh->rtnh_len > len) + break; + + index = rtnh->rtnh_ifindex; + gate = 0; + if (rtnh->rtnh_len > sizeof(*rtnh)) { + memset(tb, 0, sizeof(tb)); + netlink_parse_rtattr( + tb, RTA_MAX, RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA( + tb[RTA_GATEWAY]); + } + + if (gate) { + if (rtm->rtm_family == AF_INET) { + if (index) + rib_nexthop_ipv4_ifindex_add( + rib, gate, + prefsrc, index); + else + rib_nexthop_ipv4_add( + rib, gate, + prefsrc); + } else if (rtm->rtm_family + == AF_INET6) { + if (index) + rib_nexthop_ipv6_ifindex_add( + rib, gate, + index); + else + rib_nexthop_ipv6_add( + rib, gate); + } + } else + rib_nexthop_ifindex_add(rib, index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + zserv_nexthop_num_warn(__func__, + (const struct prefix *)&p, + rib->nexthop_num); + if (rib->nexthop_num == 0) + XFREE(MTYPE_RIB, rib); + else + rib_add_multipath(AFI_IP, SAFI_UNICAST, &p, + NULL, rib); + } + } else { + if (!tb[RTA_MULTIPATH]) + rib_delete(afi, SAFI_UNICAST, vrf_id, + ZEBRA_ROUTE_KERNEL, 0, flags, &p, NULL, gate, + index, table); + else { + struct rtnexthop *rtnh = + (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); + + for (;;) { + if (len < (int)sizeof(*rtnh) + || rtnh->rtnh_len > len) + break; + + gate = NULL; + if (rtnh->rtnh_len > sizeof(*rtnh)) { + memset(tb, 0, sizeof(tb)); + netlink_parse_rtattr( + tb, RTA_MAX, RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof(*rtnh)); + if (tb[RTA_GATEWAY]) + gate = RTA_DATA( + tb[RTA_GATEWAY]); + } + + if (gate) + rib_delete(afi, SAFI_UNICAST, vrf_id, + ZEBRA_ROUTE_KERNEL, 0, flags, + &p, NULL, gate, index, + table); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + } + } + + return 0; } static struct mcast_route_data *mroute = NULL; -static int -netlink_route_change_read_multicast (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id, int startup) +static int netlink_route_change_read_multicast(struct sockaddr_nl *snl, + struct nlmsghdr *h, + ns_id_t ns_id, int startup) { - int len; - struct rtmsg *rtm; - struct rtattr *tb[RTA_MAX + 1]; - struct mcast_route_data *m; - struct mcast_route_data mr; - int iif = 0; - int count; - int oif[256]; - int oif_count = 0; - char sbuf[40]; - char gbuf[40]; - char oif_list[256] = "\0"; - vrf_id_t vrf = ns_id; - - if (mroute) - m = mroute; - else - { - memset (&mr, 0, sizeof (mr)); - m = &mr; - } - - rtm = NLMSG_DATA (h); - - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); - - memset (tb, 0, sizeof tb); - netlink_parse_rtattr (tb, RTA_MAX, RTM_RTA (rtm), len); - - if (tb[RTA_IIF]) - iif = *(int *)RTA_DATA (tb[RTA_IIF]); - - if (tb[RTA_SRC]) - m->sg.src = *(struct in_addr *)RTA_DATA (tb[RTA_SRC]); - - if (tb[RTA_DST]) - m->sg.grp = *(struct in_addr *)RTA_DATA (tb[RTA_DST]); - - if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES]) - m->lastused = *(unsigned long long *)RTA_DATA (tb[RTA_EXPIRES]); - - if (tb[RTA_MULTIPATH]) - { - struct rtnexthop *rtnh = - (struct rtnexthop *)RTA_DATA (tb[RTA_MULTIPATH]); - - len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); - for (;;) - { - if (len < (int) sizeof (*rtnh) || rtnh->rtnh_len > len) - break; - - oif[oif_count] = rtnh->rtnh_ifindex; - oif_count++; - - len -= NLMSG_ALIGN (rtnh->rtnh_len); - rtnh = RTNH_NEXT (rtnh); - } - } - - if (IS_ZEBRA_DEBUG_KERNEL) - { - struct interface *ifp; - strcpy (sbuf, inet_ntoa (m->sg.src)); - strcpy (gbuf, inet_ntoa (m->sg.grp)); - for (count = 0; count < oif_count; count++) - { - ifp = if_lookup_by_index (oif[count], vrf); - char temp[256]; + int len; + struct rtmsg *rtm; + struct rtattr *tb[RTA_MAX + 1]; + struct mcast_route_data *m; + struct mcast_route_data mr; + int iif = 0; + int count; + int oif[256]; + int oif_count = 0; + char sbuf[40]; + char gbuf[40]; + char oif_list[256] = "\0"; + vrf_id_t vrf = ns_id; + + if (mroute) + m = mroute; + else { + memset(&mr, 0, sizeof(mr)); + m = &mr; + } + + rtm = NLMSG_DATA(h); - sprintf (temp, "%s ", ifp->name); - strcat (oif_list, temp); + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + + memset(tb, 0, sizeof tb); + netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); + + if (tb[RTA_IIF]) + iif = *(int *)RTA_DATA(tb[RTA_IIF]); + + if (tb[RTA_SRC]) + m->sg.src = *(struct in_addr *)RTA_DATA(tb[RTA_SRC]); + + if (tb[RTA_DST]) + m->sg.grp = *(struct in_addr *)RTA_DATA(tb[RTA_DST]); + + if ((RTA_EXPIRES <= RTA_MAX) && tb[RTA_EXPIRES]) + m->lastused = *(unsigned long long *)RTA_DATA(tb[RTA_EXPIRES]); + + if (tb[RTA_MULTIPATH]) { + struct rtnexthop *rtnh = + (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); + for (;;) { + if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len) + break; + + oif[oif_count] = rtnh->rtnh_ifindex; + oif_count++; + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } } - ifp = if_lookup_by_index (iif, vrf); - zlog_debug ("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld", - nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, ifp->name, oif_list, m->lastused); - } - return 0; + + if (IS_ZEBRA_DEBUG_KERNEL) { + struct interface *ifp; + strcpy(sbuf, inet_ntoa(m->sg.src)); + strcpy(gbuf, inet_ntoa(m->sg.grp)); + for (count = 0; count < oif_count; count++) { + ifp = if_lookup_by_index(oif[count], vrf); + char temp[256]; + + sprintf(temp, "%s ", ifp->name); + strcat(oif_list, temp); + } + ifp = if_lookup_by_index(iif, vrf); + zlog_debug("MCAST %s (%s,%s) IIF: %s OIF: %s jiffies: %lld", + nl_msg_type_to_str(h->nlmsg_type), sbuf, gbuf, + ifp->name, oif_list, m->lastused); + } + return 0; } -int -netlink_route_change (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id, int startup) +int netlink_route_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) { - int len; - vrf_id_t vrf_id = ns_id; - struct rtmsg *rtm; - - rtm = NLMSG_DATA (h); - - if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) - { - /* If this is not route add/delete message print warning. */ - zlog_warn ("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id); - return 0; - } - - /* Connected route. */ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("%s %s %s proto %s vrf %u", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (rtm->rtm_family), - nl_rttype_to_str (rtm->rtm_type), - nl_rtproto_to_str (rtm->rtm_protocol), - vrf_id); - - /* We don't care about change notifications for the MPLS table. */ - /* TODO: Revisit this. */ - if (rtm->rtm_family == AF_MPLS) - return 0; - - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct rtmsg)); - if (len < 0) - return -1; - - switch (rtm->rtm_type) - { - case RTN_UNICAST: - netlink_route_change_read_unicast (snl, h, ns_id, startup); - break; - case RTN_MULTICAST: - netlink_route_change_read_multicast (snl, h, ns_id, startup); - break; - default: - return 0; - break; - } - - return 0; + int len; + vrf_id_t vrf_id = ns_id; + struct rtmsg *rtm; + + rtm = NLMSG_DATA(h); + + if (!(h->nlmsg_type == RTM_NEWROUTE || h->nlmsg_type == RTM_DELROUTE)) { + /* If this is not route add/delete message print warning. */ + zlog_warn("Kernel message: %d vrf %u\n", h->nlmsg_type, vrf_id); + return 0; + } + + /* Connected route. */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s %s %s proto %s vrf %u", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(rtm->rtm_family), + nl_rttype_to_str(rtm->rtm_type), + nl_rtproto_to_str(rtm->rtm_protocol), vrf_id); + + /* We don't care about change notifications for the MPLS table. */ + /* TODO: Revisit this. */ + if (rtm->rtm_family == AF_MPLS) + return 0; + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + if (len < 0) + return -1; + + switch (rtm->rtm_type) { + case RTN_UNICAST: + netlink_route_change_read_unicast(snl, h, ns_id, startup); + break; + case RTN_MULTICAST: + netlink_route_change_read_multicast(snl, h, ns_id, startup); + break; + default: + return 0; + break; + } + + return 0; } /* Routing table read function using netlink interface. Only called bootstrap time. */ -int -netlink_route_read (struct zebra_ns *zns) +int netlink_route_read(struct zebra_ns *zns) { - int ret; - - /* Get IPv4 routing table. */ - ret = netlink_request (AF_INET, RTM_GETROUTE, &zns->netlink_cmd); - if (ret < 0) - return ret; - ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); - if (ret < 0) - return ret; - - /* Get IPv6 routing table. */ - ret = netlink_request (AF_INET6, RTM_GETROUTE, &zns->netlink_cmd); - if (ret < 0) - return ret; - ret = netlink_parse_info (netlink_route_change_read_unicast, &zns->netlink_cmd, zns, 0, 1); - if (ret < 0) - return ret; - - return 0; + int ret; + + /* Get IPv4 routing table. */ + ret = netlink_request(AF_INET, RTM_GETROUTE, &zns->netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_route_change_read_unicast, + &zns->netlink_cmd, zns, 0, 1); + if (ret < 0) + return ret; + + /* Get IPv6 routing table. */ + ret = netlink_request(AF_INET6, RTM_GETROUTE, &zns->netlink_cmd); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_route_change_read_unicast, + &zns->netlink_cmd, zns, 0, 1); + if (ret < 0) + return ret; + + return 0; } -static void -_netlink_route_nl_add_gateway_info (u_char route_family, u_char gw_family, - struct nlmsghdr *nlmsg, - size_t req_size, int bytelen, - struct nexthop *nexthop) +static void _netlink_route_nl_add_gateway_info(u_char route_family, + u_char gw_family, + struct nlmsghdr *nlmsg, + size_t req_size, int bytelen, + struct nexthop *nexthop) { - if (route_family == AF_MPLS) - { - struct gw_family_t gw_fam; - - gw_fam.family = gw_family; - if (gw_family == AF_INET) - memcpy (&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); - else - memcpy (&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - addattr_l (nlmsg, req_size, RTA_VIA, &gw_fam.family, bytelen+2); - } - else - { - if (gw_family == AF_INET) - addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); - else - addattr_l (nlmsg, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); - } + if (route_family == AF_MPLS) { + struct gw_family_t gw_fam; + + gw_fam.family = gw_family; + if (gw_family == AF_INET) + memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); + else + memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); + addattr_l(nlmsg, req_size, RTA_VIA, &gw_fam.family, + bytelen + 2); + } else { + if (gw_family == AF_INET) + addattr_l(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen); + else + addattr_l(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen); + } } -static void -_netlink_route_rta_add_gateway_info (u_char route_family, u_char gw_family, - struct rtattr *rta, struct rtnexthop *rtnh, - size_t req_size, int bytelen, - struct nexthop *nexthop) +static void _netlink_route_rta_add_gateway_info(u_char route_family, + u_char gw_family, + struct rtattr *rta, + struct rtnexthop *rtnh, + size_t req_size, int bytelen, + struct nexthop *nexthop) { - if (route_family == AF_MPLS) - { - struct gw_family_t gw_fam; - - gw_fam.family = gw_family; - if (gw_family == AF_INET) - memcpy (&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); - else - memcpy (&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - rta_addattr_l (rta, req_size, RTA_VIA, &gw_fam.family, bytelen+2); - rtnh->rtnh_len += RTA_LENGTH (bytelen + 2); - } - else - { - if (gw_family == AF_INET) - rta_addattr_l (rta, req_size, RTA_GATEWAY, &nexthop->gate.ipv4, bytelen); - else - rta_addattr_l (rta, req_size, RTA_GATEWAY, &nexthop->gate.ipv6, bytelen); - rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; - } + if (route_family == AF_MPLS) { + struct gw_family_t gw_fam; + + gw_fam.family = gw_family; + if (gw_family == AF_INET) + memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); + else + memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); + rta_addattr_l(rta, req_size, RTA_VIA, &gw_fam.family, + bytelen + 2); + rtnh->rtnh_len += RTA_LENGTH(bytelen + 2); + } else { + if (gw_family == AF_INET) + rta_addattr_l(rta, req_size, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen); + else + rta_addattr_l(rta, req_size, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen); + rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; + } } /* This function takes a nexthop as argument and adds @@ -620,188 +610,180 @@ _netlink_route_rta_add_gateway_info (u_char route_family, u_char gw_family, * @param nlmsg: nlmsghdr structure to fill in. * @param req_size: The size allocated for the message. */ -static void -_netlink_route_build_singlepath( - const char *routedesc, - int bytelen, - struct nexthop *nexthop, - struct nlmsghdr *nlmsg, - struct rtmsg *rtmsg, - size_t req_size, - int cmd) +static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, + struct nexthop *nexthop, + struct nlmsghdr *nlmsg, + struct rtmsg *rtmsg, + size_t req_size, int cmd) { - struct nexthop_label *nh_label; - mpls_lse_t out_lse[MPLS_MAX_LABELS]; - char label_buf[100]; - - if (rtmsg->rtm_family == AF_INET && - (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) - { - char buf[16] = "169.254.0.1"; - struct in_addr ipv4_ll; - - inet_pton (AF_INET, buf, &ipv4_ll); - rtmsg->rtm_flags |= RTNH_F_ONLINK; - addattr_l (nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4); - addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); - - if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug(" 5549: _netlink_route_build_singlepath() (%s): " - "nexthop via %s if %u", - routedesc, buf, nexthop->ifindex); - return; - } - - label_buf[0] = '\0'; - /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP - * (in the case of LER) - */ - nh_label = nexthop->nh_label; - if (rtmsg->rtm_family == AF_MPLS) - { - assert (nh_label); - assert (nh_label->num_labels == 1); - } - - if (nh_label && nh_label->num_labels) - { - int i, num_labels = 0; - u_int32_t bos; - char label_buf1[20]; - - for (i = 0; i < nh_label->num_labels; i++) - { - if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) - { - bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0); - out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos); - if (!num_labels) - sprintf (label_buf, "label %d", nh_label->label[i]); - else - { - sprintf (label_buf1, "/%d", nh_label->label[i]); - strcat (label_buf, label_buf1); - } - num_labels++; - } - } - if (num_labels) - { - if (rtmsg->rtm_family == AF_MPLS) - addattr_l (nlmsg, req_size, RTA_NEWDST, - &out_lse, num_labels * sizeof(mpls_lse_t)); - else - { - struct rtattr *nest; - u_int16_t encap = LWTUNNEL_ENCAP_MPLS; - - addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, - &encap, sizeof (u_int16_t)); - nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); - addattr_l (nlmsg, req_size, MPLS_IPTUNNEL_DST, - &out_lse, num_labels * sizeof(mpls_lse_t)); - addattr_nest_end(nlmsg, nest); - } - } - } - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) - rtmsg->rtm_flags |= RTNH_F_ONLINK; - - if (nexthop->type == NEXTHOP_TYPE_IPV4 - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - /* Send deletes to the kernel without specifying the next-hop */ - if (cmd != RTM_DELROUTE) - _netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET, nlmsg, - req_size, bytelen, nexthop); - - if (cmd == RTM_NEWROUTE) - { - if (nexthop->rmap_src.ipv4.s_addr) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + struct nexthop_label *nh_label; + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + char label_buf[100]; + + if (rtmsg->rtm_family == AF_INET + && (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) { + char buf[16] = "169.254.0.1"; + struct in_addr ipv4_ll; + + inet_pton(AF_INET, buf, &ipv4_ll); + rtmsg->rtm_flags |= RTNH_F_ONLINK; + addattr_l(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4); + addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); + + if (nexthop->rmap_src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr && (cmd == RTM_NEWROUTE)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + " 5549: _netlink_route_build_singlepath() (%s): " + "nexthop via %s if %u", + routedesc, buf, nexthop->ifindex); + return; } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, - inet_ntoa (nexthop->gate.ipv4), - label_buf, nexthop->ifindex); - } - if (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - { - _netlink_route_nl_add_gateway_info (rtmsg->rtm_family, AF_INET6, nlmsg, - req_size, bytelen, nexthop); - - if (cmd == RTM_NEWROUTE) - { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); + label_buf[0] = '\0'; + /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP + * (in the case of LER) + */ + nh_label = nexthop->nh_label; + if (rtmsg->rtm_family == AF_MPLS) { + assert(nh_label); + assert(nh_label->num_labels == 1); } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, - inet6_ntoa (nexthop->gate.ipv6), - label_buf, nexthop->ifindex); - } - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); - - if (cmd == RTM_NEWROUTE) - { - if (nexthop->rmap_src.ipv4.s_addr) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (nh_label && nh_label->num_labels) { + int i, num_labels = 0; + u_int32_t bos; + char label_buf1[20]; + + for (i = 0; i < nh_label->num_labels; i++) { + if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) { + bos = ((i == (nh_label->num_labels - 1)) ? 1 + : 0); + out_lse[i] = mpls_lse_encode(nh_label->label[i], + 0, 0, bos); + if (!num_labels) + sprintf(label_buf, "label %d", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%d", + nh_label->label[i]); + strcat(label_buf, label_buf1); + } + num_labels++; + } + } + if (num_labels) { + if (rtmsg->rtm_family == AF_MPLS) + addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse, + num_labels * sizeof(mpls_lse_t)); + else { + struct rtattr *nest; + u_int16_t encap = LWTUNNEL_ENCAP_MPLS; + + addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, + &encap, sizeof(u_int16_t)); + nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); + addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, + &out_lse, + num_labels * sizeof(mpls_lse_t)); + addattr_nest_end(nlmsg, nest); + } + } } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via if %u", routedesc, nexthop->ifindex); - } + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtmsg->rtm_flags |= RTNH_F_ONLINK; + + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + /* Send deletes to the kernel without specifying the next-hop */ + if (cmd != RTM_DELROUTE) + _netlink_route_nl_add_gateway_info( + rtmsg->rtm_family, AF_INET, nlmsg, req_size, + bytelen, nexthop); + + if (cmd == RTM_NEWROUTE) { + if (nexthop->rmap_src.ipv4.s_addr) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via %s %s if %u", + routedesc, inet_ntoa(nexthop->gate.ipv4), + label_buf, nexthop->ifindex); + } + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + _netlink_route_nl_add_gateway_info(rtmsg->rtm_family, AF_INET6, + nlmsg, req_size, bytelen, + nexthop); + + if (cmd == RTM_NEWROUTE) { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen); + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen); + } - if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - { - addattr32 (nlmsg, req_size, RTA_OIF, nexthop->ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via %s %s if %u", + routedesc, inet6_ntoa(nexthop->gate.ipv6), + label_buf, nexthop->ifindex); + } + if (nexthop->type == NEXTHOP_TYPE_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); + + if (cmd == RTM_NEWROUTE) { + if (nexthop->rmap_src.ipv4.s_addr) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen); + else if (nexthop->src.ipv4.s_addr) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen); + } - if (cmd == RTM_NEWROUTE) - { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l (nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via if %u", + routedesc, nexthop->ifindex); } - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via if %u", routedesc, nexthop->ifindex); - } + if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); + + if (cmd == RTM_NEWROUTE) { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen); + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + addattr_l(nlmsg, req_size, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via if %u", + routedesc, nexthop->ifindex); + } } /* This function takes a nexthop as argument and @@ -820,212 +802,201 @@ _netlink_route_build_singlepath( * @param src: pointer pointing to a location where * the prefsrc should be stored. */ -static void -_netlink_route_build_multipath( - const char *routedesc, - int bytelen, - struct nexthop *nexthop, - struct rtattr *rta, - struct rtnexthop *rtnh, - struct rtmsg *rtmsg, - union g_addr **src) +static void _netlink_route_build_multipath(const char *routedesc, int bytelen, + struct nexthop *nexthop, + struct rtattr *rta, + struct rtnexthop *rtnh, + struct rtmsg *rtmsg, + union g_addr **src) { - struct nexthop_label *nh_label; - mpls_lse_t out_lse[MPLS_MAX_LABELS]; - char label_buf[100]; - - rtnh->rtnh_len = sizeof (*rtnh); - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = 0; - rta->rta_len += rtnh->rtnh_len; - - if (rtmsg->rtm_family == AF_INET && - (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) - { - char buf[16] = "169.254.0.1"; - struct in_addr ipv4_ll; - - inet_pton (AF_INET, buf, &ipv4_ll); - bytelen = 4; - rtnh->rtnh_flags |= RTNH_F_ONLINK; - rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, - &ipv4_ll, bytelen); - rtnh->rtnh_len += sizeof (struct rtattr) + bytelen; - rtnh->rtnh_ifindex = nexthop->ifindex; - - if (nexthop->rmap_src.ipv4.s_addr) - *src = &nexthop->rmap_src; - else if (nexthop->src.ipv4.s_addr) - *src = &nexthop->src; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug(" 5549: netlink_route_build_multipath() (%s): " - "nexthop via %s if %u", - routedesc, buf, nexthop->ifindex); - return; - } - - label_buf[0] = '\0'; - /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP - * (in the case of LER) - */ - nh_label = nexthop->nh_label; - if (rtmsg->rtm_family == AF_MPLS) - { - assert (nh_label); - assert (nh_label->num_labels == 1); - } - - if (nh_label && nh_label->num_labels) - { - int i, num_labels = 0; - u_int32_t bos; - char label_buf1[20]; - - for (i = 0; i < nh_label->num_labels; i++) - { - if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) - { - bos = ((i == (nh_label->num_labels - 1)) ? 1 : 0); - out_lse[i] = mpls_lse_encode (nh_label->label[i], 0, 0, bos); - if (!num_labels) - sprintf (label_buf, "label %d", nh_label->label[i]); - else - { - sprintf (label_buf1, "/%d", nh_label->label[i]); - strcat (label_buf, label_buf1); - } - num_labels++; - } - } - if (num_labels) - { - if (rtmsg->rtm_family == AF_MPLS) - { - rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTA_NEWDST, - &out_lse, num_labels * sizeof(mpls_lse_t)); - rtnh->rtnh_len += RTA_LENGTH (num_labels * sizeof(mpls_lse_t)); - } - else - { - struct rtattr *nest; - u_int16_t encap = LWTUNNEL_ENCAP_MPLS; - int len = rta->rta_len; - - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE, - &encap, sizeof (u_int16_t)); - nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP); - rta_addattr_l (rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST, - &out_lse, num_labels * sizeof(mpls_lse_t)); - rta_nest_end(rta, nest); - rtnh->rtnh_len += rta->rta_len - len; - } - } - } - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) - rtnh->rtnh_flags |= RTNH_F_ONLINK; - - if (nexthop->type == NEXTHOP_TYPE_IPV4 - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - { - _netlink_route_rta_add_gateway_info (rtmsg->rtm_family, AF_INET, rta, - rtnh, NL_PKT_BUF_SIZE, bytelen, nexthop); - if (nexthop->rmap_src.ipv4.s_addr) - *src = &nexthop->rmap_src; - else if (nexthop->src.ipv4.s_addr) - *src = &nexthop->src; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, - inet_ntoa (nexthop->gate.ipv4), - label_buf, nexthop->ifindex); - } - if (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - { - _netlink_route_rta_add_gateway_info (rtmsg->rtm_family, AF_INET6, rta, - rtnh, NL_PKT_BUF_SIZE, bytelen, nexthop); - - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - *src = &nexthop->rmap_src; - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - *src = &nexthop->src; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via %s %s if %u", - routedesc, - inet6_ntoa (nexthop->gate.ipv6), - label_buf, nexthop->ifindex); - } - /* ifindex */ - if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IFINDEX) - { - rtnh->rtnh_ifindex = nexthop->ifindex; - - if (nexthop->rmap_src.ipv4.s_addr) - *src = &nexthop->rmap_src; - else if (nexthop->src.ipv4.s_addr) - *src = &nexthop->src; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via if %u", routedesc, nexthop->ifindex); - } - else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - { - rtnh->rtnh_ifindex = nexthop->ifindex; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via if %u", routedesc, nexthop->ifindex); - } - else - { - rtnh->rtnh_ifindex = 0; - } + struct nexthop_label *nh_label; + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + char label_buf[100]; + + rtnh->rtnh_len = sizeof(*rtnh); + rtnh->rtnh_flags = 0; + rtnh->rtnh_hops = 0; + rta->rta_len += rtnh->rtnh_len; + + if (rtmsg->rtm_family == AF_INET + && (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) { + char buf[16] = "169.254.0.1"; + struct in_addr ipv4_ll; + + inet_pton(AF_INET, buf, &ipv4_ll); + bytelen = 4; + rtnh->rtnh_flags |= RTNH_F_ONLINK; + rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &ipv4_ll, + bytelen); + rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; + rtnh->rtnh_ifindex = nexthop->ifindex; + + if (nexthop->rmap_src.ipv4.s_addr) + *src = &nexthop->rmap_src; + else if (nexthop->src.ipv4.s_addr) + *src = &nexthop->src; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + " 5549: netlink_route_build_multipath() (%s): " + "nexthop via %s if %u", + routedesc, buf, nexthop->ifindex); + return; + } + + label_buf[0] = '\0'; + /* outgoing label - either as NEWDST (in the case of LSR) or as ENCAP + * (in the case of LER) + */ + nh_label = nexthop->nh_label; + if (rtmsg->rtm_family == AF_MPLS) { + assert(nh_label); + assert(nh_label->num_labels == 1); + } + + if (nh_label && nh_label->num_labels) { + int i, num_labels = 0; + u_int32_t bos; + char label_buf1[20]; + + for (i = 0; i < nh_label->num_labels; i++) { + if (nh_label->label[i] != MPLS_IMP_NULL_LABEL) { + bos = ((i == (nh_label->num_labels - 1)) ? 1 + : 0); + out_lse[i] = mpls_lse_encode(nh_label->label[i], + 0, 0, bos); + if (!num_labels) + sprintf(label_buf, "label %d", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%d", + nh_label->label[i]); + strcat(label_buf, label_buf1); + } + num_labels++; + } + } + if (num_labels) { + if (rtmsg->rtm_family == AF_MPLS) { + rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST, + &out_lse, + num_labels * sizeof(mpls_lse_t)); + rtnh->rtnh_len += RTA_LENGTH( + num_labels * sizeof(mpls_lse_t)); + } else { + struct rtattr *nest; + u_int16_t encap = LWTUNNEL_ENCAP_MPLS; + int len = rta->rta_len; + + rta_addattr_l(rta, NL_PKT_BUF_SIZE, + RTA_ENCAP_TYPE, &encap, + sizeof(u_int16_t)); + nest = rta_nest(rta, NL_PKT_BUF_SIZE, + RTA_ENCAP); + rta_addattr_l(rta, NL_PKT_BUF_SIZE, + MPLS_IPTUNNEL_DST, &out_lse, + num_labels * sizeof(mpls_lse_t)); + rta_nest_end(rta, nest); + rtnh->rtnh_len += rta->rta_len - len; + } + } + } + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtnh->rtnh_flags |= RTNH_F_ONLINK; + + if (nexthop->type == NEXTHOP_TYPE_IPV4 + || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { + _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET, + rta, rtnh, NL_PKT_BUF_SIZE, + bytelen, nexthop); + if (nexthop->rmap_src.ipv4.s_addr) + *src = &nexthop->rmap_src; + else if (nexthop->src.ipv4.s_addr) + *src = &nexthop->src; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via %s %s if %u", + routedesc, inet_ntoa(nexthop->gate.ipv4), + label_buf, nexthop->ifindex); + } + if (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET6, + rta, rtnh, NL_PKT_BUF_SIZE, + bytelen, nexthop); + + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) + *src = &nexthop->rmap_src; + else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) + *src = &nexthop->src; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via %s %s if %u", + routedesc, inet6_ntoa(nexthop->gate.ipv6), + label_buf, nexthop->ifindex); + } + /* ifindex */ + if (nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX + || nexthop->type == NEXTHOP_TYPE_IFINDEX) { + rtnh->rtnh_ifindex = nexthop->ifindex; + + if (nexthop->rmap_src.ipv4.s_addr) + *src = &nexthop->rmap_src; + else if (nexthop->src.ipv4.s_addr) + *src = &nexthop->src; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via if %u", + routedesc, nexthop->ifindex); + } else if (nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { + rtnh->rtnh_ifindex = nexthop->ifindex; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath() (%s): " + "nexthop via if %u", + routedesc, nexthop->ifindex); + } else { + rtnh->rtnh_ifindex = 0; + } } -static inline void -_netlink_mpls_build_singlepath( - const char *routedesc, - zebra_nhlfe_t *nhlfe, - struct nlmsghdr *nlmsg, - struct rtmsg *rtmsg, - size_t req_size, - int cmd) +static inline void _netlink_mpls_build_singlepath(const char *routedesc, + zebra_nhlfe_t *nhlfe, + struct nlmsghdr *nlmsg, + struct rtmsg *rtmsg, + size_t req_size, int cmd) { - int bytelen; - u_char family; + int bytelen; + u_char family; - family = NHLFE_FAMILY (nhlfe); - bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_singlepath(routedesc, bytelen, nhlfe->nexthop, - nlmsg, rtmsg, req_size, cmd); + family = NHLFE_FAMILY(nhlfe); + bytelen = (family == AF_INET ? 4 : 16); + _netlink_route_build_singlepath(routedesc, bytelen, nhlfe->nexthop, + nlmsg, rtmsg, req_size, cmd); } static inline void -_netlink_mpls_build_multipath( - const char *routedesc, - zebra_nhlfe_t *nhlfe, - struct rtattr *rta, - struct rtnexthop *rtnh, - struct rtmsg *rtmsg, - union g_addr **src) +_netlink_mpls_build_multipath(const char *routedesc, zebra_nhlfe_t *nhlfe, + struct rtattr *rta, struct rtnexthop *rtnh, + struct rtmsg *rtmsg, union g_addr **src) { - int bytelen; - u_char family; + int bytelen; + u_char family; - family = NHLFE_FAMILY (nhlfe); - bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_multipath(routedesc, bytelen, nhlfe->nexthop, - rta, rtnh, rtmsg, src); + family = NHLFE_FAMILY(nhlfe); + bytelen = (family == AF_INET ? 4 : 16); + _netlink_route_build_multipath(routedesc, bytelen, nhlfe->nexthop, rta, + rtnh, rtmsg, src); } @@ -1039,603 +1010,609 @@ _netlink_mpls_build_multipath( * (recursive, multipath, etc.) * @param family: Address family which the change concerns */ -static void -_netlink_route_debug( - int cmd, - struct prefix *p, - struct nexthop *nexthop, - const char *routedesc, - int family, - struct zebra_vrf *zvrf) +static void _netlink_route_debug(int cmd, struct prefix *p, + struct nexthop *nexthop, const char *routedesc, + int family, struct zebra_vrf *zvrf) { - if (IS_ZEBRA_DEBUG_KERNEL) - { - char buf[PREFIX_STRLEN]; - zlog_debug ("netlink_route_multipath() (%s): %s %s vrf %u type %s", - routedesc, - nl_msg_type_to_str (cmd), - prefix2str (p, buf, sizeof(buf)), zvrf_id (zvrf), - (nexthop) ? nexthop_type_to_str (nexthop->type) : "UNK"); - } - } - -static void -_netlink_mpls_debug( - int cmd, - u_int32_t label, - const char *routedesc) -{ - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("netlink_mpls_multipath() (%s): %s %u/20", - routedesc, nl_msg_type_to_str (cmd), label); + if (IS_ZEBRA_DEBUG_KERNEL) { + char buf[PREFIX_STRLEN]; + zlog_debug( + "netlink_route_multipath() (%s): %s %s vrf %u type %s", + routedesc, nl_msg_type_to_str(cmd), + prefix2str(p, buf, sizeof(buf)), zvrf_id(zvrf), + (nexthop) ? nexthop_type_to_str(nexthop->type) : "UNK"); + } } -static int -netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen) +static void _netlink_mpls_debug(int cmd, u_int32_t label, const char *routedesc) { - struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH - req.ndm.ndm_family = AF_INET; - req.ndm.ndm_state = NUD_PERMANENT; - req.ndm.ndm_ifindex = ifindex; - req.ndm.ndm_type = RTN_UNICAST; - - addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); - addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("netlink_mpls_multipath() (%s): %s %u/20", routedesc, + nl_msg_type_to_str(cmd), label); +} - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); +static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, + int llalen) +{ + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH + req.ndm.ndm_family = AF_INET; + req.ndm.ndm_state = NUD_PERMANENT; + req.ndm.ndm_ifindex = ifindex; + req.ndm.ndm_type = RTN_UNICAST; + + addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); + addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } /* Routing table change via netlink interface. */ /* Update flag indicates whether this is a "replace" or not. */ -static int -netlink_route_multipath (int cmd, struct prefix *p, struct prefix *src_p, - struct rib *rib, int update) +static int netlink_route_multipath(int cmd, struct prefix *p, + struct prefix *src_p, struct rib *rib, + int update) { - int bytelen; - struct sockaddr_nl snl; - struct nexthop *nexthop = NULL, *tnexthop; - int recursing; - unsigned int nexthop_num; - int discard; - int family = PREFIX_FAMILY(p); - const char *routedesc; - int setsrc = 0; - union g_addr src; - - struct - { - struct nlmsghdr n; - struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; - - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - struct zebra_vrf *zvrf = vrf_info_lookup (rib->vrf_id); - - memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); - - bytelen = (family == AF_INET ? 4 : 16); - - req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - if ((cmd == RTM_NEWROUTE) && update) - req.n.nlmsg_flags |= NLM_F_REPLACE; - req.n.nlmsg_type = cmd; - req.r.rtm_family = family; - req.r.rtm_dst_len = p->prefixlen; - req.r.rtm_src_len = src_p ? src_p->prefixlen : 0; - req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - - if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) || (rib->flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) - { - if (discard) - { - if (rib->flags & ZEBRA_FLAG_BLACKHOLE) - req.r.rtm_type = RTN_BLACKHOLE; - else if (rib->flags & ZEBRA_FLAG_REJECT) - req.r.rtm_type = RTN_UNREACHABLE; - else - assert (RTN_BLACKHOLE != RTN_UNREACHABLE); /* false */ - } - else - req.r.rtm_type = RTN_UNICAST; - } - - addattr_l (&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); - if (src_p) - addattr_l (&req.n, sizeof req, RTA_SRC, &src_p->u.prefix, bytelen); - - /* Metric. */ - /* Hardcode the metric for all routes coming from zebra. Metric isn't used - * either by the kernel or by zebra. Its purely for calculating best path(s) - * by the routing protocol and for communicating with protocol peers. - */ - addattr32 (&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); - - /* Table corresponding to this route. */ - if (rib->table < 256) - req.r.rtm_table = rib->table; - else - { - req.r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req.n, sizeof req, RTA_TABLE, rib->table); - } - - if (rib->mtu || rib->nexthop_mtu) - { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *) buf; - u_int32_t mtu = rib->mtu; - if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) - mtu = rib->nexthop_mtu; - rta->rta_type = RTA_METRICS; - rta->rta_len = RTA_LENGTH(0); - rta_addattr_l (rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); - addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA (rta), - RTA_PAYLOAD (rta)); - } - - if (discard) - { - if (cmd == RTM_NEWROUTE) - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - /* We shouldn't encounter recursive nexthops on discard routes, - * but it is probably better to handle that case correctly anyway. - */ - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - } - goto skip; - } - - /* Count overall nexthops so we can decide whether to use singlepath - * or multipath case. */ - nexthop_num = 0; - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - if (cmd == RTM_NEWROUTE && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - continue; - if (cmd == RTM_DELROUTE && !CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - continue; - - nexthop_num++; - } - - /* Singlepath case. */ - if (nexthop_num == 1 || multipath_num == 1) - { - nexthop_num = 0; - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - { - if (!setsrc) - { - if (family == AF_INET) - { - if (nexthop->rmap_src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->rmap_src.ipv4; - setsrc = 1; - } - else if (nexthop->src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->src.ipv4; - setsrc = 1; - } - } - else if (family == AF_INET6) - { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - { - src.ipv6 = nexthop->rmap_src.ipv6; - setsrc = 1; - } - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - { - src.ipv6 = nexthop->src.ipv6; - setsrc = 1; - } - } - } - continue; - } - - if ((cmd == RTM_NEWROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == RTM_DELROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - routedesc = recursing ? "recursive, 1 hop" : "single hop"; - - _netlink_route_debug(cmd, p, nexthop, routedesc, family, zvrf); - _netlink_route_build_singlepath(routedesc, bytelen, - nexthop, &req.n, &req.r, - sizeof req, cmd); - nexthop_num++; - break; - } - } - if (setsrc && (cmd == RTM_NEWROUTE)) - { - if (family == AF_INET) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); - else if (family == AF_INET6) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen); + int bytelen; + struct sockaddr_nl snl; + struct nexthop *nexthop = NULL, *tnexthop; + int recursing; + unsigned int nexthop_num; + int discard; + int family = PREFIX_FAMILY(p); + const char *routedesc; + int setsrc = 0; + union g_addr src; + + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[NL_PKT_BUF_SIZE]; + } req; + + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct zebra_vrf *zvrf = vrf_info_lookup(rib->vrf_id); + + memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + + bytelen = (family == AF_INET ? 4 : 16); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + if ((cmd == RTM_NEWROUTE) && update) + req.n.nlmsg_flags |= NLM_F_REPLACE; + req.n.nlmsg_type = cmd; + req.r.rtm_family = family; + req.r.rtm_dst_len = p->prefixlen; + req.r.rtm_src_len = src_p ? src_p->prefixlen : 0; + req.r.rtm_protocol = RTPROT_ZEBRA; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + + if ((rib->flags & ZEBRA_FLAG_BLACKHOLE) + || (rib->flags & ZEBRA_FLAG_REJECT)) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) { + if (discard) { + if (rib->flags & ZEBRA_FLAG_BLACKHOLE) + req.r.rtm_type = RTN_BLACKHOLE; + else if (rib->flags & ZEBRA_FLAG_REJECT) + req.r.rtm_type = RTN_UNREACHABLE; + else + assert(RTN_BLACKHOLE + != RTN_UNREACHABLE); /* false */ + } else + req.r.rtm_type = RTN_UNICAST; } - } - else - { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *) buf; - struct rtnexthop *rtnh; - union g_addr *src1 = NULL; - - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH (0); - rtnh = RTA_DATA (rta); - - nexthop_num = 0; - for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) - { - if (nexthop_num >= multipath_num) - break; - - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - { - /* This only works for IPv4 now */ - if (!setsrc) - { - if (family == AF_INET) - { - if (nexthop->rmap_src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->rmap_src.ipv4; - setsrc = 1; - } - else if (nexthop->src.ipv4.s_addr != 0) - { - src.ipv4 = nexthop->src.ipv4; - setsrc = 1; - } - } - else if (family == AF_INET6) - { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - { - src.ipv6 = nexthop->rmap_src.ipv6; - setsrc = 1; - } - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - { - src.ipv6 = nexthop->src.ipv6; - setsrc = 1; - } - } - } - continue; - } - - if ((cmd == RTM_NEWROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - || (cmd == RTM_DELROUTE - && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))) - { - routedesc = recursing ? "recursive, multihop" : "multihop"; - nexthop_num++; - - _netlink_route_debug(cmd, p, nexthop, - routedesc, family, zvrf); - _netlink_route_build_multipath(routedesc, bytelen, - nexthop, rta, rtnh, &req.r, &src1); - rtnh = RTNH_NEXT (rtnh); - - if (!setsrc && src1) - { - if (family == AF_INET) - src.ipv4 = src1->ipv4; - else if (family == AF_INET6) - src.ipv6 = src1->ipv6; - setsrc = 1; - } - } - } - if (setsrc && (cmd == RTM_NEWROUTE)) - { - if (family == AF_INET) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv4, bytelen); - else if (family == AF_INET6) - addattr_l (&req.n, sizeof req, RTA_PREFSRC, &src.ipv6, bytelen); - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Setting source"); + addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); + if (src_p) + addattr_l(&req.n, sizeof req, RTA_SRC, &src_p->u.prefix, + bytelen); + + /* Metric. */ + /* Hardcode the metric for all routes coming from zebra. Metric isn't + * used + * either by the kernel or by zebra. Its purely for calculating best + * path(s) + * by the routing protocol and for communicating with protocol peers. + */ + addattr32(&req.n, sizeof req, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); + + /* Table corresponding to this route. */ + if (rib->table < 256) + req.r.rtm_table = rib->table; + else { + req.r.rtm_table = RT_TABLE_UNSPEC; + addattr32(&req.n, sizeof req, RTA_TABLE, rib->table); + } + + if (rib->mtu || rib->nexthop_mtu) { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *)buf; + u_int32_t mtu = rib->mtu; + if (!mtu || (rib->nexthop_mtu && rib->nexthop_mtu < mtu)) + mtu = rib->nexthop_mtu; + rta->rta_type = RTA_METRICS; + rta->rta_len = RTA_LENGTH(0); + rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTAX_MTU, &mtu, sizeof mtu); + addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_METRICS, RTA_DATA(rta), + RTA_PAYLOAD(rta)); } - if (rta->rta_len > RTA_LENGTH (0)) - addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), - RTA_PAYLOAD (rta)); - } + if (discard) { + if (cmd == RTM_NEWROUTE) + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, + recursing)) { + /* We shouldn't encounter recursive nexthops on + * discard routes, + * but it is probably better to handle that case + * correctly anyway. + */ + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + } + goto skip; + } - /* If there is no useful nexthop then return. */ - if (nexthop_num == 0) - { - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("netlink_route_multipath(): No useful nexthop."); - return 0; - } + /* Count overall nexthops so we can decide whether to use singlepath + * or multipath case. */ + nexthop_num = 0; + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) { + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + continue; + if (cmd == RTM_NEWROUTE + && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + continue; + if (cmd == RTM_DELROUTE + && !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) + continue; + + nexthop_num++; + } + + /* Singlepath case. */ + if (nexthop_num == 1 || multipath_num == 1) { + nexthop_num = 0; + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, + recursing)) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) { + if (!setsrc) { + if (family == AF_INET) { + if (nexthop->rmap_src.ipv4 + .s_addr + != 0) { + src.ipv4 = + nexthop->rmap_src + .ipv4; + setsrc = 1; + } else if (nexthop->src.ipv4 + .s_addr + != 0) { + src.ipv4 = + nexthop->src + .ipv4; + setsrc = 1; + } + } else if (family == AF_INET6) { + if (!IN6_IS_ADDR_UNSPECIFIED( + &nexthop->rmap_src + .ipv6)) { + src.ipv6 = + nexthop->rmap_src + .ipv6; + setsrc = 1; + } else if ( + !IN6_IS_ADDR_UNSPECIFIED( + &nexthop->src + .ipv6)) { + src.ipv6 = + nexthop->src + .ipv6; + setsrc = 1; + } + } + } + continue; + } + + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB))) { + routedesc = recursing ? "recursive, 1 hop" + : "single hop"; + + _netlink_route_debug(cmd, p, nexthop, routedesc, + family, zvrf); + _netlink_route_build_singlepath( + routedesc, bytelen, nexthop, &req.n, + &req.r, sizeof req, cmd); + nexthop_num++; + break; + } + } + if (setsrc && (cmd == RTM_NEWROUTE)) { + if (family == AF_INET) + addattr_l(&req.n, sizeof req, RTA_PREFSRC, + &src.ipv4, bytelen); + else if (family == AF_INET6) + addattr_l(&req.n, sizeof req, RTA_PREFSRC, + &src.ipv6, bytelen); + } + } else { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *)buf; + struct rtnexthop *rtnh; + union g_addr *src1 = NULL; + + rta->rta_type = RTA_MULTIPATH; + rta->rta_len = RTA_LENGTH(0); + rtnh = RTA_DATA(rta); + + nexthop_num = 0; + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, + recursing)) { + if (nexthop_num >= multipath_num) + break; + + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) { + /* This only works for IPv4 now */ + if (!setsrc) { + if (family == AF_INET) { + if (nexthop->rmap_src.ipv4 + .s_addr + != 0) { + src.ipv4 = + nexthop->rmap_src + .ipv4; + setsrc = 1; + } else if (nexthop->src.ipv4 + .s_addr + != 0) { + src.ipv4 = + nexthop->src + .ipv4; + setsrc = 1; + } + } else if (family == AF_INET6) { + if (!IN6_IS_ADDR_UNSPECIFIED( + &nexthop->rmap_src + .ipv6)) { + src.ipv6 = + nexthop->rmap_src + .ipv6; + setsrc = 1; + } else if ( + !IN6_IS_ADDR_UNSPECIFIED( + &nexthop->src + .ipv6)) { + src.ipv6 = + nexthop->src + .ipv6; + setsrc = 1; + } + } + } + continue; + } + + if ((cmd == RTM_NEWROUTE + && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + || (cmd == RTM_DELROUTE + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB))) { + routedesc = recursing ? "recursive, multihop" + : "multihop"; + nexthop_num++; + + _netlink_route_debug(cmd, p, nexthop, routedesc, + family, zvrf); + _netlink_route_build_multipath( + routedesc, bytelen, nexthop, rta, rtnh, + &req.r, &src1); + rtnh = RTNH_NEXT(rtnh); + + if (!setsrc && src1) { + if (family == AF_INET) + src.ipv4 = src1->ipv4; + else if (family == AF_INET6) + src.ipv6 = src1->ipv6; + + setsrc = 1; + } + } + } + if (setsrc && (cmd == RTM_NEWROUTE)) { + if (family == AF_INET) + addattr_l(&req.n, sizeof req, RTA_PREFSRC, + &src.ipv4, bytelen); + else if (family == AF_INET6) + addattr_l(&req.n, sizeof req, RTA_PREFSRC, + &src.ipv6, bytelen); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Setting source"); + } + + if (rta->rta_len > RTA_LENGTH(0)) + addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, + RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + + /* If there is no useful nexthop then return. */ + if (nexthop_num == 0) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "netlink_route_multipath(): No useful nexthop."); + return 0; + } skip: - /* Destination netlink address. */ - memset (&snl, 0, sizeof snl); - snl.nl_family = AF_NETLINK; + /* Destination netlink address. */ + memset(&snl, 0, sizeof snl); + snl.nl_family = AF_NETLINK; - /* Talk to netlink socket. */ - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); + /* Talk to netlink socket. */ + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } -int -kernel_get_ipmr_sg_stats (void *in) +int kernel_get_ipmr_sg_stats(void *in) { - int suc = 0; - struct mcast_route_data *mr = (struct mcast_route_data *)in; - struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - - mroute = mr; - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); - - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.n.nlmsg_flags = NLM_F_REQUEST; - req.ndm.ndm_family = AF_INET; - req.n.nlmsg_type = RTM_GETROUTE; - - addattr_l (&req.n, sizeof (req), RTA_IIF, &mroute->ifindex, 4); - addattr_l (&req.n, sizeof (req), RTA_OIF, &mroute->ifindex, 4); - addattr_l (&req.n, sizeof (req), RTA_SRC, &mroute->sg.src.s_addr, 4); - addattr_l (&req.n, sizeof (req), RTA_DST, &mroute->sg.grp.s_addr, 4); - - suc = netlink_talk (netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0); - - mroute = NULL; - return suc; + int suc = 0; + struct mcast_route_data *mr = (struct mcast_route_data *)in; + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + + mroute = mr; + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + memset(&req.n, 0, sizeof(req.n)); + memset(&req.ndm, 0, sizeof(req.ndm)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.ndm.ndm_family = AF_INET; + req.n.nlmsg_type = RTM_GETROUTE; + + addattr_l(&req.n, sizeof(req), RTA_IIF, &mroute->ifindex, 4); + addattr_l(&req.n, sizeof(req), RTA_OIF, &mroute->ifindex, 4); + addattr_l(&req.n, sizeof(req), RTA_SRC, &mroute->sg.src.s_addr, 4); + addattr_l(&req.n, sizeof(req), RTA_DST, &mroute->sg.grp.s_addr, 4); + + suc = netlink_talk(netlink_route_change_read_multicast, &req.n, + &zns->netlink_cmd, zns, 0); + + mroute = NULL; + return suc; } -int -kernel_route_rib (struct prefix *p, struct prefix *src_p, - struct rib *old, struct rib *new) +int kernel_route_rib(struct prefix *p, struct prefix *src_p, struct rib *old, + struct rib *new) { - if (!old && new) - return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 0); - if (old && !new) - return netlink_route_multipath (RTM_DELROUTE, p, src_p, old, 0); + if (!old && new) + return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 0); + if (old && !new) + return netlink_route_multipath(RTM_DELROUTE, p, src_p, old, 0); - return netlink_route_multipath (RTM_NEWROUTE, p, src_p, new, 1); + return netlink_route_multipath(RTM_NEWROUTE, p, src_p, new, 1); } -int -kernel_neigh_update (int add, int ifindex, uint32_t addr, char *lla, int llalen) +int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, + int llalen) { - return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, addr, - lla, llalen); + return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, + addr, lla, llalen); } /* * MPLS label forwarding table change via netlink interface. */ -int -netlink_mpls_multipath (int cmd, zebra_lsp_t *lsp) +int netlink_mpls_multipath(int cmd, zebra_lsp_t *lsp) { - mpls_lse_t lse; - zebra_nhlfe_t *nhlfe; - struct nexthop *nexthop = NULL; - unsigned int nexthop_num; - const char *routedesc; - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - - struct - { - struct nlmsghdr n; - struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; - - memset (&req, 0, sizeof req - NL_PKT_BUF_SIZE); - - - /* - * Count # nexthops so we can decide whether to use singlepath - * or multipath case. - */ - nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - nexthop = nhlfe->nexthop; - if (!nexthop) - continue; - if (cmd == RTM_NEWROUTE) - { - /* Count all selected NHLFEs */ - if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - nexthop_num++; - } - else /* DEL */ - { - /* Count all installed NHLFEs */ - if (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - nexthop_num++; - } - } - - if (nexthop_num == 0) // unexpected - return 0; - - req.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - req.n.nlmsg_type = cmd; - req.r.rtm_family = AF_MPLS; - req.r.rtm_table = RT_TABLE_MAIN; - req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS; - req.r.rtm_protocol = RTPROT_ZEBRA; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - req.r.rtm_type = RTN_UNICAST; - - if (cmd == RTM_NEWROUTE) - /* We do a replace to handle update. */ - req.n.nlmsg_flags |= NLM_F_REPLACE; - - /* Fill destination */ - lse = mpls_lse_encode (lsp->ile.in_label, 0, 0, 1); - addattr_l (&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t)); - - /* Fill nexthops (paths) based on single-path or multipath. The paths - * chosen depend on the operation. - */ - if (nexthop_num == 1 || multipath_num == 1) - { - routedesc = "single hop"; - _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); - - nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - nexthop = nhlfe->nexthop; - if (!nexthop) - continue; - - if ((cmd == RTM_NEWROUTE && - (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) || - (cmd == RTM_DELROUTE && - (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))) - { - /* Add the gateway */ - _netlink_mpls_build_singlepath(routedesc, nhlfe, - &req.n, &req.r, sizeof req, cmd); - if (cmd == RTM_NEWROUTE) - { - SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } - else - { - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } - nexthop_num++; - break; - } - } - } - else /* Multipath case */ - { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *) buf; - struct rtnexthop *rtnh; - union g_addr *src1 = NULL; - - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH (0); - rtnh = RTA_DATA (rta); - - routedesc = "multihop"; - _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); - - nexthop_num = 0; - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - nexthop = nhlfe->nexthop; - if (!nexthop) - continue; - - if (nexthop_num >= multipath_num) - break; - - if ((cmd == RTM_NEWROUTE && - (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_SELECTED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))) || - (cmd == RTM_DELROUTE && - (CHECK_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED) && - CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)))) - { - nexthop_num++; - - /* Build the multipath */ - _netlink_mpls_build_multipath(routedesc, nhlfe, rta, - rtnh, &req.r, &src1); - rtnh = RTNH_NEXT (rtnh); - - if (cmd == RTM_NEWROUTE) - { - SET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } - else - { - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } - - } - } - - /* Add the multipath */ - if (rta->rta_len > RTA_LENGTH (0)) - addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), - RTA_PAYLOAD (rta)); - } - - /* Talk to netlink socket. */ - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); + mpls_lse_t lse; + zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop = NULL; + unsigned int nexthop_num; + const char *routedesc; + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + + struct { + struct nlmsghdr n; + struct rtmsg r; + char buf[NL_PKT_BUF_SIZE]; + } req; + + memset(&req, 0, sizeof req - NL_PKT_BUF_SIZE); + + + /* + * Count # nexthops so we can decide whether to use singlepath + * or multipath case. + */ + nexthop_num = 0; + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + nexthop = nhlfe->nexthop; + if (!nexthop) + continue; + if (cmd == RTM_NEWROUTE) { + /* Count all selected NHLFEs */ + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) + && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + nexthop_num++; + } else /* DEL */ + { + /* Count all installed NHLFEs */ + if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) + && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)) + nexthop_num++; + } + } + + if (nexthop_num == 0) // unexpected + return 0; + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req.n.nlmsg_type = cmd; + req.r.rtm_family = AF_MPLS; + req.r.rtm_table = RT_TABLE_MAIN; + req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS; + req.r.rtm_protocol = RTPROT_ZEBRA; + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + req.r.rtm_type = RTN_UNICAST; + + if (cmd == RTM_NEWROUTE) + /* We do a replace to handle update. */ + req.n.nlmsg_flags |= NLM_F_REPLACE; + + /* Fill destination */ + lse = mpls_lse_encode(lsp->ile.in_label, 0, 0, 1); + addattr_l(&req.n, sizeof req, RTA_DST, &lse, sizeof(mpls_lse_t)); + + /* Fill nexthops (paths) based on single-path or multipath. The paths + * chosen depend on the operation. + */ + if (nexthop_num == 1 || multipath_num == 1) { + routedesc = "single hop"; + _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); + + nexthop_num = 0; + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + nexthop = nhlfe->nexthop; + if (!nexthop) + continue; + + if ((cmd == RTM_NEWROUTE + && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_ACTIVE))) + || (cmd == RTM_DELROUTE + && (CHECK_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED) + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB)))) { + /* Add the gateway */ + _netlink_mpls_build_singlepath(routedesc, nhlfe, + &req.n, &req.r, + sizeof req, cmd); + if (cmd == RTM_NEWROUTE) { + SET_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED); + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); + } else { + UNSET_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED); + UNSET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); + } + nexthop_num++; + break; + } + } + } else /* Multipath case */ + { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *)buf; + struct rtnexthop *rtnh; + union g_addr *src1 = NULL; + + rta->rta_type = RTA_MULTIPATH; + rta->rta_len = RTA_LENGTH(0); + rtnh = RTA_DATA(rta); + + routedesc = "multihop"; + _netlink_mpls_debug(cmd, lsp->ile.in_label, routedesc); + + nexthop_num = 0; + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + nexthop = nhlfe->nexthop; + if (!nexthop) + continue; + + if (nexthop_num >= multipath_num) + break; + + if ((cmd == RTM_NEWROUTE + && (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED) + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_ACTIVE))) + || (cmd == RTM_DELROUTE + && (CHECK_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED) + && CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB)))) { + nexthop_num++; + + /* Build the multipath */ + _netlink_mpls_build_multipath(routedesc, nhlfe, + rta, rtnh, &req.r, + &src1); + rtnh = RTNH_NEXT(rtnh); + + if (cmd == RTM_NEWROUTE) { + SET_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED); + SET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); + } else { + UNSET_FLAG(nhlfe->flags, + NHLFE_FLAG_INSTALLED); + UNSET_FLAG(nexthop->flags, + NEXTHOP_FLAG_FIB); + } + } + } + + /* Add the multipath */ + if (rta->rta_len > RTA_LENGTH(0)) + addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, + RTA_DATA(rta), RTA_PAYLOAD(rta)); + } + + /* Talk to netlink socket. */ + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } /* * Handle failure in LSP install, clear flags for NHLFE. */ -void -clear_nhlfe_installed (zebra_lsp_t *lsp) +void clear_nhlfe_installed(zebra_lsp_t *lsp) { - zebra_nhlfe_t *nhlfe; - struct nexthop *nexthop; - - for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) - { - nexthop = nhlfe->nexthop; - if (!nexthop) - continue; - - UNSET_FLAG (nhlfe->flags, NHLFE_FLAG_INSTALLED); - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); - } + zebra_nhlfe_t *nhlfe; + struct nexthop *nexthop; + + for (nhlfe = lsp->nhlfe_list; nhlfe; nhlfe = nhlfe->next) { + nexthop = nhlfe->nexthop; + if (!nexthop) + continue; + + UNSET_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED); + UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + } } |
