diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 4093 |
1 files changed, 2029 insertions, 2064 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index e017eb78e3..c02774ca64 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -119,11 +119,10 @@ static vlanid_t filter_vlan = 0; -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; }; char ipv4_ll_buf[16] = "169.254.0.1"; @@ -135,592 +134,582 @@ struct in_addr ipv4_ll; * correct value one time instead for every * install/remove of a 5549 type route */ -void -rt_netlink_init (void) +void rt_netlink_init(void) { - inet_pton (AF_INET, ipv4_ll_buf, &ipv4_ll); + inet_pton(AF_INET, ipv4_ll_buf, &ipv4_ll); } static inline int is_selfroute(int proto) { - if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) || - (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) || - (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG) || - (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP) || - (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)) { - return 1; - } - - return 0; + if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) + || (proto == RTPROT_STATIC) || (proto == RTPROT_ZEBRA) + || (proto == RTPROT_ISIS) || (proto == RTPROT_RIPNG) + || (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP) + || (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)) { + return 1; + } + + return 0; } static inline int get_rt_proto(int proto) { - switch (proto) { - case ZEBRA_ROUTE_BABEL: - proto = RTPROT_BABEL; - break; - case ZEBRA_ROUTE_BGP: - proto = RTPROT_BGP; - break; - case ZEBRA_ROUTE_OSPF: - case ZEBRA_ROUTE_OSPF6: - proto = RTPROT_OSPF; - break; - case ZEBRA_ROUTE_STATIC: - proto = RTPROT_STATIC; - break; - case ZEBRA_ROUTE_ISIS: - proto = RTPROT_ISIS; - break; - case ZEBRA_ROUTE_RIP: - proto = RTPROT_RIP; - break; - case ZEBRA_ROUTE_RIPNG: - proto = RTPROT_RIPNG; - break; - case ZEBRA_ROUTE_NHRP: - proto = RTPROT_NHRP; - break; - case ZEBRA_ROUTE_EIGRP: - proto = RTPROT_EIGRP; - break; - case ZEBRA_ROUTE_LDP: - proto = RTPROT_LDP; - break; - default: - proto = RTPROT_ZEBRA; - break; - } - - return proto; + switch (proto) { + case ZEBRA_ROUTE_BABEL: + proto = RTPROT_BABEL; + break; + case ZEBRA_ROUTE_BGP: + proto = RTPROT_BGP; + break; + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + proto = RTPROT_OSPF; + break; + case ZEBRA_ROUTE_STATIC: + proto = RTPROT_STATIC; + break; + case ZEBRA_ROUTE_ISIS: + proto = RTPROT_ISIS; + break; + case ZEBRA_ROUTE_RIP: + proto = RTPROT_RIP; + break; + case ZEBRA_ROUTE_RIPNG: + proto = RTPROT_RIPNG; + break; + case ZEBRA_ROUTE_NHRP: + proto = RTPROT_NHRP; + break; + case ZEBRA_ROUTE_EIGRP: + proto = RTPROT_EIGRP; + break; + case ZEBRA_ROUTE_LDP: + proto = RTPROT_LDP; + break; + default: + proto = RTPROT_ZEBRA; + break; + } + + return proto; } /* 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 && - is_selfroute (rtm->rtm_protocol) && - 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 (is_selfroute(rtm->rtm_protocol)) - 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; - - src_p.prefixlen = 0; // Forces debug below to not display anything - } - 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 route_entry *re; - struct rtnexthop *rtnh = - (struct rtnexthop *) RTA_DATA (tb[RTA_MULTIPATH]); - - len = RTA_PAYLOAD (tb[RTA_MULTIPATH]); - - re = XCALLOC (MTYPE_RE, sizeof (struct route_entry)); - re->type = ZEBRA_ROUTE_KERNEL; - re->distance = 0; - re->flags = flags; - re->metric = metric; - re->mtu = mtu; - re->vrf_id = vrf_id; - re->table = table; - re->nexthop_num = 0; - re->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) - route_entry_nexthop_ipv4_ifindex_add (re, gate, prefsrc, index); - else - route_entry_nexthop_ipv4_add (re, gate, prefsrc); - } - else if (rtm->rtm_family == AF_INET6) - { - if (index) - route_entry_nexthop_ipv6_ifindex_add (re, gate, index); - else - route_entry_nexthop_ipv6_add (re,gate); - } - } - else - route_entry_nexthop_ifindex_add (re, index); - - len -= NLMSG_ALIGN(rtnh->rtnh_len); - rtnh = RTNH_NEXT(rtnh); - } - - zserv_nexthop_num_warn(__func__, (const struct prefix *)&p, - re->nexthop_num); - if (re->nexthop_num == 0) - XFREE (MTYPE_RE, re); - else - rib_add_multipath (AFI_IP, SAFI_UNICAST, &p, NULL, re); - } - } - 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 && is_selfroute(rtm->rtm_protocol) + && 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 (is_selfroute(rtm->rtm_protocol)) + 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; + + src_p.prefixlen = + 0; // Forces debug below to not display anything + } 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 route_entry *re; + struct rtnexthop *rtnh = + (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); + + len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); + + re = XCALLOC(MTYPE_RE, sizeof(struct route_entry)); + re->type = ZEBRA_ROUTE_KERNEL; + re->distance = 0; + re->flags = flags; + re->metric = metric; + re->mtu = mtu; + re->vrf_id = vrf_id; + re->table = table; + re->nexthop_num = 0; + re->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) + route_entry_nexthop_ipv4_ifindex_add( + re, gate, + prefsrc, index); + else + route_entry_nexthop_ipv4_add( + re, gate, + prefsrc); + } else if (rtm->rtm_family + == AF_INET6) { + if (index) + route_entry_nexthop_ipv6_ifindex_add( + re, gate, + index); + else + route_entry_nexthop_ipv6_add( + re, gate); + } + } else + route_entry_nexthop_ifindex_add(re, + index); + + len -= NLMSG_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } + + zserv_nexthop_num_warn(__func__, + (const struct prefix *)&p, + re->nexthop_num); + if (re->nexthop_num == 0) + XFREE(MTYPE_RE, re); + else + rib_add_multipath(AFI_IP, SAFI_UNICAST, &p, + NULL, re); + } + } 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); + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); + + memset(tb, 0, sizeof tb); + netlink_parse_rtattr(tb, RTA_MAX, RTM_RTA(rtm), len); - sprintf (temp, "%s ", ifp->name); - strcat (oif_list, temp); + 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]; + + 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); } - 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; + 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; } /* Request for specific route information from the kernel */ -static int -netlink_request_route (struct zebra_ns *zns, int family, int type) +static int netlink_request_route(struct zebra_ns *zns, int family, int type) { - struct - { - struct nlmsghdr n; - struct rtmsg rtm; - } req; - - /* Form the request, specifying filter (rtattr) if needed. */ - memset (&req, 0, sizeof (req)); - req.n.nlmsg_type = type; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.rtm.rtm_family = family; - - return netlink_request (&zns->netlink_cmd, &req.n); + struct { + struct nlmsghdr n; + struct rtmsg rtm; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req.rtm.rtm_family = family; + + return netlink_request(&zns->netlink_cmd, &req.n); } /* 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_route (zns, AF_INET, RTM_GETROUTE); - 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_route (zns, AF_INET6, RTM_GETROUTE); - 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_route(zns, AF_INET, RTM_GETROUTE); + 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_route(zns, AF_INET6, RTM_GETROUTE); + 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 @@ -734,194 +723,186 @@ _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]; - - /* - * label_buf is *only* currently used within debugging. - * As such when we assign it we are guarding it inside - * a debug test. If you want to change this make sure - * you fix this assumption - */ - 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 (IS_ZEBRA_DEBUG_KERNEL) - { - 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); - } + struct nexthop_label *nh_label; + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + char label_buf[100]; + + /* + * label_buf is *only* currently used within debugging. + * As such when we assign it we are guarding it inside + * a debug test. If you want to change this make sure + * you fix this assumption + */ + 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 (IS_ZEBRA_DEBUG_KERNEL) { + 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); + } } - 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 (rtmsg->rtm_family == AF_INET && - (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) - { - 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 %s if %u", - routedesc, ipv4_ll_buf, label_buf, nexthop->ifindex); - return; - } - - 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 (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtmsg->rtm_flags |= RTNH_F_ONLINK; + + if (rtmsg->rtm_family == AF_INET + && (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) { + 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 %s if %u", + routedesc, ipv4_ll_buf, label_buf, + nexthop->ifindex); + return; } - 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 (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 (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_route_multipath() (%s): " - "nexthop via if %u", routedesc, 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 @@ -940,217 +921,206 @@ _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; - - /* - * label_buf is *only* currently used within debugging. - * As such when we assign it we are guarding it inside - * a debug test. If you want to change this make sure - * you fix this assumption - */ - 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 (IS_ZEBRA_DEBUG_KERNEL) - { - 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); - } + 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; + + /* + * label_buf is *only* currently used within debugging. + * As such when we assign it we are guarding it inside + * a debug test. If you want to change this make sure + * you fix this assumption + */ + 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 (IS_ZEBRA_DEBUG_KERNEL) { + 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; + } } - 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 (rtmsg->rtm_family == AF_INET && - (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) - { - 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 %s if %u", - routedesc, ipv4_ll_buf, label_buf, nexthop->ifindex); - return; - } - - 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; - } + } + + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) + rtnh->rtnh_flags |= RTNH_F_ONLINK; + + if (rtmsg->rtm_family == AF_INET + && (nexthop->type == NEXTHOP_TYPE_IPV6 + || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)) { + 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 %s if %u", + routedesc, ipv4_ll_buf, label_buf, + nexthop->ifindex); + return; + } + + 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); } @@ -1164,1316 +1134,1311 @@ _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) { + 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) + zlog_debug("netlink_mpls_multipath() (%s): %s %u/20", routedesc, + nl_msg_type_to_str(cmd), label); } -static int -netlink_neigh_update (int cmd, int ifindex, uint32_t addr, char *lla, int llalen) +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 { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); - memset(&req.n, 0, sizeof(req.n)); - memset(&req.ndm, 0, sizeof(req.ndm)); + 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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + 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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - req.ndm.ndm_family = AF_INET; - req.ndm.ndm_state = NUD_PERMANENT; - req.ndm.ndm_ifindex = ifindex; - req.ndm.ndm_type = RTN_UNICAST; + 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); + 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); + 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 route_entry *re, int update) +static int netlink_route_multipath(int cmd, struct prefix *p, + struct prefix *src_p, struct route_entry *re, + int update) { - int bytelen; - struct sockaddr_nl snl; - struct nexthop *nexthop = NULL; - 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 (re->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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - - 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 = get_rt_proto(re->type); - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - - if ((re->flags & ZEBRA_FLAG_BLACKHOLE) || (re->flags & ZEBRA_FLAG_REJECT)) - discard = 1; - else - discard = 0; - - if (cmd == RTM_NEWROUTE) - { - if (discard) - { - if (re->flags & ZEBRA_FLAG_BLACKHOLE) - req.r.rtm_type = RTN_BLACKHOLE; - else if (re->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 (re->table < 256) - req.r.rtm_table = re->table; - else - { - req.r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req.n, sizeof req, RTA_TABLE, re->table); - } - - if (re->mtu || re->nexthop_mtu) - { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *) buf; - u_int32_t mtu = re->mtu; - if (!mtu || (re->nexthop_mtu && re->nexthop_mtu < mtu)) - mtu = re->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(re->nexthop, nexthop)) - { - /* 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(re->nexthop, nexthop)) - { - 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(re->nexthop, nexthop)) - { - 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 = nexthop->rparent ? "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; + 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(re->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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + + 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 = get_rt_proto(re->type); + req.r.rtm_scope = RT_SCOPE_UNIVERSE; + + if ((re->flags & ZEBRA_FLAG_BLACKHOLE) + || (re->flags & ZEBRA_FLAG_REJECT)) + discard = 1; + else + discard = 0; + + if (cmd == RTM_NEWROUTE) { + if (discard) { + if (re->flags & ZEBRA_FLAG_BLACKHOLE) + req.r.rtm_type = RTN_BLACKHOLE; + else if (re->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(re->nexthop, nexthop)) - { - 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 = nexthop->rparent ? "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 (re->table < 256) + req.r.rtm_table = re->table; + else { + req.r.rtm_table = RT_TABLE_UNSPEC; + addattr32(&req.n, sizeof req, RTA_TABLE, re->table); } - if (rta->rta_len > RTA_LENGTH (0)) - addattr_l (&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, RTA_DATA (rta), - RTA_PAYLOAD (rta)); - } + if (re->mtu || re->nexthop_mtu) { + char buf[NL_PKT_BUF_SIZE]; + struct rtattr *rta = (void *)buf; + u_int32_t mtu = re->mtu; + if (!mtu || (re->nexthop_mtu && re->nexthop_mtu < mtu)) + mtu = re->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(re->nexthop, nexthop)) { + /* 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(re->nexthop, nexthop)) { + 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(re->nexthop, nexthop)) { + 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 = nexthop->rparent + ? "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(re->nexthop, nexthop)) { + 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 = nexthop->rparent + ? "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; - } + /* 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; + 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); + 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)); + 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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - req.ndm.ndm_family = AF_INET; - req.n.nlmsg_type = RTM_GETROUTE; + 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); + 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); + suc = netlink_talk(netlink_route_change_read_multicast, &req.n, + &zns->netlink_cmd, zns, 0); - mroute = NULL; - return suc; + mroute = NULL; + return suc; } -int -kernel_route_rib (struct prefix *p, struct prefix *src_p, - struct route_entry *old, struct route_entry *new) +int kernel_route_rib(struct prefix *p, struct prefix *src_p, + struct route_entry *old, struct route_entry *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); } /* * Add remote VTEP to the flood list for this VxLAN interface (VNI). This * is done by adding an FDB entry with a MAC of 00:00:00:00:00:00. */ -static int -netlink_vxlan_flood_list_update (struct interface *ifp, - struct in_addr *vtep_ip, - int cmd) +static int netlink_vxlan_flood_list_update(struct interface *ifp, + struct in_addr *vtep_ip, int cmd) { - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - struct - { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - u_char dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - - 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; - if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND); - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = PF_BRIDGE; - req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT; - req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" - - - addattr_l (&req.n, sizeof (req), NDA_LLADDR, &dst_mac, 6); - req.ndm.ndm_ifindex = ifp->ifindex; - addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip->s_addr, 4); - - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + u_char dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + + 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; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_APPEND); + req.n.nlmsg_type = cmd; + req.ndm.ndm_family = PF_BRIDGE; + req.ndm.ndm_state = NUD_NOARP | NUD_PERMANENT; + req.ndm.ndm_flags |= NTF_SELF; // Handle by "self", not "master" + + + addattr_l(&req.n, sizeof(req), NDA_LLADDR, &dst_mac, 6); + req.ndm.ndm_ifindex = ifp->ifindex; + addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip->s_addr, 4); + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } /* - * Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves adding + * Add remote VTEP for this VxLAN interface (VNI). In Linux, this involves + * adding * a "flood" MAC FDB entry. */ -int -kernel_add_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +int kernel_add_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("Install %s into flood list for VNI %u intf %s(%u)", - inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("Install %s into flood list for VNI %u intf %s(%u)", + inet_ntoa(*vtep_ip), vni, ifp->name, ifp->ifindex); - return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_NEWNEIGH); + return netlink_vxlan_flood_list_update(ifp, vtep_ip, RTM_NEWNEIGH); } /* * Remove remote VTEP for this VxLAN interface (VNI). In Linux, this involves * deleting the "flood" MAC FDB entry. */ -int -kernel_del_vtep (vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) +int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) { - if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug ("Uninstall %s from flood list for VNI %u intf %s(%u)", - inet_ntoa (*vtep_ip), vni, ifp->name, ifp->ifindex); + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "Uninstall %s from flood list for VNI %u intf %s(%u)", + inet_ntoa(*vtep_ip), vni, ifp->name, ifp->ifindex); - return netlink_vxlan_flood_list_update (ifp, vtep_ip, RTM_DELNEIGH); + return netlink_vxlan_flood_list_update(ifp, vtep_ip, RTM_DELNEIGH); } #ifndef NDA_RTA -#define NDA_RTA(r) \ - ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) +#define NDA_RTA(r) \ + ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) #endif -static int -netlink_macfdb_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) +static int netlink_macfdb_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + int len) { - struct ndmsg *ndm; - struct interface *ifp; - struct zebra_if *zif; - struct zebra_vrf *zvrf; - struct rtattr *tb[NDA_MAX + 1]; - struct interface *br_if; - struct ethaddr mac; - vlanid_t vid = 0; - struct prefix vtep_ip; - int vid_present = 0, dst_present = 0; - char buf[ETHER_ADDR_STRLEN]; - char vid_buf[20]; - char dst_buf[30]; - u_char sticky = 0; - - ndm = NLMSG_DATA (h); - - /* The interface should exist. */ - ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex); - if (!ifp) - return 0; - - /* Locate VRF corresponding to interface. We only process MAC notifications - * if EVPN is enabled on this VRF. - */ - zvrf = vrf_info_lookup(ifp->vrf_id); - if (!zvrf || !EVPN_ENABLED(zvrf)) - return 0; - if (!ifp->info) - return 0; - - /* The interface should be something we're interested in. */ - if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) - return 0; - - /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) - return 0; - - zif = (struct zebra_if *)ifp->info; - if ((br_if = zif->brslave_info.br_if) == NULL) - { - zlog_warn ("%s family %s IF %s(%u) brIF %u - no bridge master", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - zif->brslave_info.bridge_ifindex); - return 0; - } - - /* Parse attributes and extract fields of interest. */ - memset (tb, 0, sizeof tb); - netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len); - - if (!tb[NDA_LLADDR]) - { - zlog_warn ("%s family %s IF %s(%u) brIF %u - no LLADDR", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - zif->brslave_info.bridge_ifindex); - return 0; - } - - if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN) - { - zlog_warn ("%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - zif->brslave_info.bridge_ifindex, - RTA_PAYLOAD (tb[NDA_LLADDR])); - return 0; - } - - memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN); - - if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN]) - { - vid_present = 1; - vid = *(u_int16_t *) RTA_DATA(tb[NDA_VLAN]); - sprintf (vid_buf, " VLAN %u", vid); - } - - if (tb[NDA_DST]) - { - /* TODO: Only IPv4 supported now. */ - dst_present = 1; - vtep_ip.family = AF_INET; - vtep_ip.prefixlen = IPV4_MAX_BITLEN; - memcpy (&(vtep_ip.u.prefix4.s_addr), RTA_DATA (tb[NDA_DST]), IPV4_MAX_BYTELEN); - sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip.u.prefix4)); - } - - sticky = (ndm->ndm_state & NUD_NOARP) ? 1 : 0; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Rx %s family %s IF %s(%u)%s %sMAC %s%s", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - vid_present ? vid_buf : "", - sticky ? "sticky " : "", - prefix_mac2str (&mac, buf, sizeof (buf)), - dst_present ? dst_buf: ""); - - if (filter_vlan && vid != filter_vlan) - return 0; - - /* If add or update, do accordingly if learnt on a "local" interface; if - * the notification is over VxLAN, this has to be related to multi-homing, - * so perform an implicit delete of any local entry (if it exists). - */ - if (h->nlmsg_type == RTM_NEWNEIGH) - { - /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) - return 0; - - if (IS_ZEBRA_IF_VXLAN(ifp)) - return zebra_vxlan_check_del_local_mac (ifp, br_if, &mac, vid); - - return zebra_vxlan_local_mac_add_update (ifp, br_if, &mac, vid, sticky); - } - - /* This is a delete notification. - * 1. For a MAC over VxLan, check if it needs to be refreshed(readded) - * 2. For a MAC over "local" interface, delete the mac - * Note: We will get notifications from both bridge driver and VxLAN driver. - * Ignore the notification from VxLan driver as it is also generated - * when mac moves from remote to local. - */ - if (dst_present) - return 0; - - if (IS_ZEBRA_IF_VXLAN(ifp)) - return zebra_vxlan_check_readd_remote_mac (ifp, br_if, &mac, vid); - - return zebra_vxlan_local_mac_del (ifp, br_if, &mac, vid); + struct ndmsg *ndm; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct rtattr *tb[NDA_MAX + 1]; + struct interface *br_if; + struct ethaddr mac; + vlanid_t vid = 0; + struct prefix vtep_ip; + int vid_present = 0, dst_present = 0; + char buf[ETHER_ADDR_STRLEN]; + char vid_buf[20]; + char dst_buf[30]; + u_char sticky = 0; + + ndm = NLMSG_DATA(h); + + /* The interface should exist. */ + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + ndm->ndm_ifindex); + if (!ifp) + return 0; + + /* Locate VRF corresponding to interface. We only process MAC + * notifications + * if EVPN is enabled on this VRF. + */ + zvrf = vrf_info_lookup(ifp->vrf_id); + if (!zvrf || !EVPN_ENABLED(zvrf)) + return 0; + if (!ifp->info) + return 0; + + /* The interface should be something we're interested in. */ + if (!IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) + return 0; + + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + zif = (struct zebra_if *)ifp->info; + if ((br_if = zif->brslave_info.br_if) == NULL) { + zlog_warn("%s family %s IF %s(%u) brIF %u - no bridge master", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + return 0; + } + + /* Parse attributes and extract fields of interest. */ + memset(tb, 0, sizeof tb); + netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); + + if (!tb[NDA_LLADDR]) { + zlog_warn("%s family %s IF %s(%u) brIF %u - no LLADDR", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex); + return 0; + } + + if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) { + zlog_warn( + "%s family %s IF %s(%u) brIF %u - LLADDR is not MAC, len %ld", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, zif->brslave_info.bridge_ifindex, + RTA_PAYLOAD(tb[NDA_LLADDR])); + return 0; + } + + memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN); + + if ((NDA_VLAN <= NDA_MAX) && tb[NDA_VLAN]) { + vid_present = 1; + vid = *(u_int16_t *)RTA_DATA(tb[NDA_VLAN]); + sprintf(vid_buf, " VLAN %u", vid); + } + + if (tb[NDA_DST]) { + /* TODO: Only IPv4 supported now. */ + dst_present = 1; + vtep_ip.family = AF_INET; + vtep_ip.prefixlen = IPV4_MAX_BITLEN; + memcpy(&(vtep_ip.u.prefix4.s_addr), RTA_DATA(tb[NDA_DST]), + IPV4_MAX_BYTELEN); + sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip.u.prefix4)); + } + + sticky = (ndm->ndm_state & NUD_NOARP) ? 1 : 0; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Rx %s family %s IF %s(%u)%s %sMAC %s%s", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, vid_present ? vid_buf : "", + sticky ? "sticky " : "", + prefix_mac2str(&mac, buf, sizeof(buf)), + dst_present ? dst_buf : ""); + + if (filter_vlan && vid != filter_vlan) + return 0; + + /* If add or update, do accordingly if learnt on a "local" interface; if + * the notification is over VxLAN, this has to be related to + * multi-homing, + * so perform an implicit delete of any local entry (if it exists). + */ + if (h->nlmsg_type == RTM_NEWNEIGH) { + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return zebra_vxlan_check_del_local_mac(ifp, br_if, &mac, + vid); + + return zebra_vxlan_local_mac_add_update(ifp, br_if, &mac, vid, + sticky); + } + + /* This is a delete notification. + * 1. For a MAC over VxLan, check if it needs to be refreshed(readded) + * 2. For a MAC over "local" interface, delete the mac + * Note: We will get notifications from both bridge driver and VxLAN + * driver. + * Ignore the notification from VxLan driver as it is also generated + * when mac moves from remote to local. + */ + if (dst_present) + return 0; + + if (IS_ZEBRA_IF_VXLAN(ifp)) + return zebra_vxlan_check_readd_remote_mac(ifp, br_if, &mac, + vid); + + return zebra_vxlan_local_mac_del(ifp, br_if, &mac, vid); } -static int -netlink_macfdb_table (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id, int startup) +static int netlink_macfdb_table(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) { - int len; - struct ndmsg *ndm; + int len; + struct ndmsg *ndm; - if (h->nlmsg_type != RTM_NEWNEIGH) - return 0; + if (h->nlmsg_type != RTM_NEWNEIGH) + return 0; - /* Length validity. */ - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); - if (len < 0) - return -1; + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg)); + if (len < 0) + return -1; - /* We are interested only in AF_BRIDGE notifications. */ - ndm = NLMSG_DATA (h); - if (ndm->ndm_family != AF_BRIDGE) - return 0; + /* We are interested only in AF_BRIDGE notifications. */ + ndm = NLMSG_DATA(h); + if (ndm->ndm_family != AF_BRIDGE) + return 0; - return netlink_macfdb_change (snl, h, len); + return netlink_macfdb_change(snl, h, len); } /* Request for MAC FDB information from the kernel */ -static int -netlink_request_macs (struct zebra_ns *zns, int family, int type, - ifindex_t master_ifindex) +static int netlink_request_macs(struct zebra_ns *zns, int family, int type, + ifindex_t master_ifindex) { - struct - { - struct nlmsghdr n; - struct ifinfomsg ifm; - char buf[256]; - } req; - - /* Form the request, specifying filter (rtattr) if needed. */ - memset (&req, 0, sizeof (req)); - req.n.nlmsg_type = type; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); - req.ifm.ifi_family = family; - if (master_ifindex) - addattr32 (&req.n, sizeof(req), IFLA_MASTER, master_ifindex); - - return netlink_request (&zns->netlink_cmd, &req.n); + struct { + struct nlmsghdr n; + struct ifinfomsg ifm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.ifm.ifi_family = family; + if (master_ifindex) + addattr32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); + + return netlink_request(&zns->netlink_cmd, &req.n); } /* * MAC forwarding database read using netlink interface. This is invoked * at startup. */ -int -netlink_macfdb_read (struct zebra_ns *zns) +int netlink_macfdb_read(struct zebra_ns *zns) { - int ret; - - /* Get bridge FDB table. */ - ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, 0); - if (ret < 0) - return ret; - /* We are reading entire table. */ - filter_vlan = 0; - ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 1); - - return ret; + int ret; + + /* Get bridge FDB table. */ + ret = netlink_request_macs(zns, AF_BRIDGE, RTM_GETNEIGH, 0); + if (ret < 0) + return ret; + /* We are reading entire table. */ + filter_vlan = 0; + ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd, zns, + 0, 1); + + return ret; } /* * MAC forwarding database read using netlink interface. This is for a * specific bridge and matching specific access VLAN (if VLAN-aware bridge). */ -int -netlink_macfdb_read_for_bridge (struct zebra_ns *zns, struct interface *ifp, - struct interface *br_if) +int netlink_macfdb_read_for_bridge(struct zebra_ns *zns, struct interface *ifp, + struct interface *br_if) { - struct zebra_if *br_zif; - struct zebra_if *zif; - struct zebra_l2info_vxlan *vxl; - int ret = 0; - - - /* Save VLAN we're filtering on, if needed. */ - br_zif = (struct zebra_if *) br_if->info; - zif = (struct zebra_if *) ifp->info; - vxl = &zif->l2info.vxl; - if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) - filter_vlan = vxl->access_vlan; - - /* Get bridge FDB table for specific bridge - we do the VLAN filtering. */ - ret = netlink_request_macs (zns, AF_BRIDGE, RTM_GETNEIGH, br_if->ifindex); - if (ret < 0) - return ret; - ret = netlink_parse_info (netlink_macfdb_table, &zns->netlink_cmd, zns, 0, 0); - - /* Reset VLAN filter. */ - filter_vlan = 0; - return ret; + struct zebra_if *br_zif; + struct zebra_if *zif; + struct zebra_l2info_vxlan *vxl; + int ret = 0; + + + /* Save VLAN we're filtering on, if needed. */ + br_zif = (struct zebra_if *)br_if->info; + zif = (struct zebra_if *)ifp->info; + vxl = &zif->l2info.vxl; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif)) + filter_vlan = vxl->access_vlan; + + /* Get bridge FDB table for specific bridge - we do the VLAN filtering. + */ + ret = netlink_request_macs(zns, AF_BRIDGE, RTM_GETNEIGH, + br_if->ifindex); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_macfdb_table, &zns->netlink_cmd, zns, + 0, 0); + + /* Reset VLAN filter. */ + filter_vlan = 0; + return ret; } -static int -netlink_macfdb_update (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, - struct in_addr vtep_ip, - int local, int cmd, - u_char sticky) +static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, + struct ethaddr *mac, struct in_addr vtep_ip, + int local, int cmd, u_char sticky) { - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - struct - { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - int dst_alen; - struct zebra_if *zif; - struct interface *br_if; - struct zebra_if *br_zif; - char buf[ETHER_ADDR_STRLEN]; - int vid_present = 0, dst_present = 0; - char vid_buf[20]; - char dst_buf[30]; - - zif = ifp->info; - if ((br_if = zif->brslave_info.br_if) == NULL) - { - zlog_warn ("MAC %s on IF %s(%u) - no mapping to bridge", - (cmd == RTM_NEWNEIGH) ? "add" : "del", - ifp->name, ifp->ifindex); - return -1; - } - - 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; - if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); - req.n.nlmsg_type = cmd; - req.ndm.ndm_family = AF_BRIDGE; - req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; - req.ndm.ndm_state = NUD_REACHABLE; - - if (sticky) - req.ndm.ndm_state |= NUD_NOARP; - else - req.ndm.ndm_flags |= NTF_EXT_LEARNED; - - addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); - req.ndm.ndm_ifindex = ifp->ifindex; - if (!local) - { - dst_alen = 4; // TODO: hardcoded - addattr_l (&req.n, sizeof (req), NDA_DST, &vtep_ip, dst_alen); - dst_present = 1; - sprintf (dst_buf, " dst %s", inet_ntoa (vtep_ip)); - } - br_zif = (struct zebra_if *) br_if->info; - if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) - { - addattr16 (&req.n, sizeof (req), NDA_VLAN, vid); - vid_present = 1; - sprintf (vid_buf, " VLAN %u", vid); - } - addattr32 (&req.n, sizeof (req), NDA_MASTER, br_if->ifindex); - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Tx %s family %s IF %s(%u)%s %sMAC %s%s", - nl_msg_type_to_str (cmd), - nl_family_to_str (req.ndm.ndm_family), - ifp->name, ifp->ifindex, - vid_present ? vid_buf : "", - sticky ? "sticky " : "", - prefix_mac2str (mac, buf, sizeof (buf)), - dst_present ? dst_buf : ""); - - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int dst_alen; + struct zebra_if *zif; + struct interface *br_if; + struct zebra_if *br_zif; + char buf[ETHER_ADDR_STRLEN]; + int vid_present = 0, dst_present = 0; + char vid_buf[20]; + char dst_buf[30]; + + zif = ifp->info; + if ((br_if = zif->brslave_info.br_if) == NULL) { + zlog_warn("MAC %s on IF %s(%u) - no mapping to bridge", + (cmd == RTM_NEWNEIGH) ? "add" : "del", ifp->name, + ifp->ifindex); + return -1; + } + + 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; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; + req.ndm.ndm_family = AF_BRIDGE; + req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; + req.ndm.ndm_state = NUD_REACHABLE; + + if (sticky) + req.ndm.ndm_state |= NUD_NOARP; + else + req.ndm.ndm_flags |= NTF_EXT_LEARNED; + + addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + req.ndm.ndm_ifindex = ifp->ifindex; + if (!local) { + dst_alen = 4; // TODO: hardcoded + addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen); + dst_present = 1; + sprintf(dst_buf, " dst %s", inet_ntoa(vtep_ip)); + } + br_zif = (struct zebra_if *)br_if->info; + if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) { + addattr16(&req.n, sizeof(req), NDA_VLAN, vid); + vid_present = 1; + sprintf(vid_buf, " VLAN %u", vid); + } + addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Tx %s family %s IF %s(%u)%s %sMAC %s%s", + nl_msg_type_to_str(cmd), + nl_family_to_str(req.ndm.ndm_family), ifp->name, + ifp->ifindex, vid_present ? vid_buf : "", + sticky ? "sticky " : "", + prefix_mac2str(mac, buf, sizeof(buf)), + dst_present ? dst_buf : ""); + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } -#define NUD_VALID (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | \ - NUD_PROBE | NUD_STALE | NUD_DELAY) +#define NUD_VALID \ + (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE | NUD_PROBE | NUD_STALE \ + | NUD_DELAY) -static int -netlink_ipneigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, int len) +static int netlink_ipneigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + int len) { - struct ndmsg *ndm; - struct interface *ifp; - struct zebra_if *zif; - struct zebra_vrf *zvrf; - struct rtattr *tb[NDA_MAX + 1]; - struct interface *link_if; - struct ethaddr mac; - struct ipaddr ip; - char buf[ETHER_ADDR_STRLEN]; - char buf2[INET6_ADDRSTRLEN]; - int mac_present = 0; - u_char ext_learned; - - ndm = NLMSG_DATA (h); - - /* The interface should exist. */ - ifp = if_lookup_by_index_per_ns (zebra_ns_lookup (NS_DEFAULT), ndm->ndm_ifindex); - if (!ifp) - return 0; - - /* Locate VRF corresponding to interface. We only process neigh notifications - * if EVPN is enabled on this VRF. - */ - zvrf = vrf_info_lookup(ifp->vrf_id); - if (!zvrf || !EVPN_ENABLED(zvrf)) - return 0; - if (!ifp->info) - return 0; - - /* Drop "permanent" entries. */ - if (ndm->ndm_state & NUD_PERMANENT) - return 0; - - zif = (struct zebra_if *)ifp->info; - /* The neighbor is present on an SVI. From this, we locate the underlying - * bridge because we're only interested in neighbors on a VxLAN bridge. - * The bridge is located based on the nature of the SVI: - * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN interface - * and is linked to the bridge - * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge inteface - * itself - */ - if (IS_ZEBRA_IF_VLAN(ifp)) - { - link_if = zif->link; - if (!link_if) - return 0; - } - else if (IS_ZEBRA_IF_BRIDGE(ifp)) - link_if = ifp; - else - return 0; - - /* Parse attributes and extract fields of interest. */ - memset (tb, 0, sizeof tb); - netlink_parse_rtattr (tb, NDA_MAX, NDA_RTA (ndm), len); - - if (!tb[NDA_DST]) - { - zlog_warn ("%s family %s IF %s(%u) - no DST", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex); - return 0; - } - memset (&mac, 0, sizeof (struct ethaddr)); - memset (&ip, 0, sizeof (struct ipaddr)); - ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6; - memcpy (&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); - - if (h->nlmsg_type == RTM_NEWNEIGH) - { - if (tb[NDA_LLADDR]) - { - if (RTA_PAYLOAD (tb[NDA_LLADDR]) != ETHER_ADDR_LEN) - { - zlog_warn ("%s family %s IF %s(%u) - LLADDR is not MAC, len %ld", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - RTA_PAYLOAD (tb[NDA_LLADDR])); - return 0; - } - - mac_present = 1; - memcpy (&mac, RTA_DATA (tb[NDA_LLADDR]), ETHER_ADDR_LEN); - } - - ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - ipaddr2str (&ip, buf2, sizeof(buf2)), - mac_present ? prefix_mac2str (&mac, buf, sizeof (buf)) : "", - ndm->ndm_state, ndm->ndm_flags); - - /* If the neighbor state is valid for use, process as an add or update - * else process as a delete. Note that the delete handling may result - * in re-adding the neighbor if it is a valid "remote" neighbor. - */ - if (ndm->ndm_state & NUD_VALID) - return zebra_vxlan_local_neigh_add_update (ifp, link_if, - &ip, &mac, - ndm->ndm_state, ext_learned); - - return zebra_vxlan_local_neigh_del (ifp, link_if, &ip); - } - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Rx %s family %s IF %s(%u) IP %s", - nl_msg_type_to_str (h->nlmsg_type), - nl_family_to_str (ndm->ndm_family), - ifp->name, ndm->ndm_ifindex, - ipaddr2str (&ip, buf2, sizeof(buf2))); - - /* Process the delete - it may result in re-adding the neighbor if it is - * a valid "remote" neighbor. - */ - return zebra_vxlan_local_neigh_del (ifp, link_if, &ip); + struct ndmsg *ndm; + struct interface *ifp; + struct zebra_if *zif; + struct zebra_vrf *zvrf; + struct rtattr *tb[NDA_MAX + 1]; + struct interface *link_if; + struct ethaddr mac; + struct ipaddr ip; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + int mac_present = 0; + u_char ext_learned; + + ndm = NLMSG_DATA(h); + + /* The interface should exist. */ + ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), + ndm->ndm_ifindex); + if (!ifp) + return 0; + + /* Locate VRF corresponding to interface. We only process neigh + * notifications + * if EVPN is enabled on this VRF. + */ + zvrf = vrf_info_lookup(ifp->vrf_id); + if (!zvrf || !EVPN_ENABLED(zvrf)) + return 0; + if (!ifp->info) + return 0; + + /* Drop "permanent" entries. */ + if (ndm->ndm_state & NUD_PERMANENT) + return 0; + + zif = (struct zebra_if *)ifp->info; + /* The neighbor is present on an SVI. From this, we locate the + * underlying + * bridge because we're only interested in neighbors on a VxLAN bridge. + * The bridge is located based on the nature of the SVI: + * (a) In the case of a VLAN-aware bridge, the SVI is a L3 VLAN + * interface + * and is linked to the bridge + * (b) In the case of a VLAN-unaware bridge, the SVI is the bridge + * inteface + * itself + */ + if (IS_ZEBRA_IF_VLAN(ifp)) { + link_if = zif->link; + if (!link_if) + return 0; + } else if (IS_ZEBRA_IF_BRIDGE(ifp)) + link_if = ifp; + else + return 0; + + /* Parse attributes and extract fields of interest. */ + memset(tb, 0, sizeof tb); + netlink_parse_rtattr(tb, NDA_MAX, NDA_RTA(ndm), len); + + if (!tb[NDA_DST]) { + zlog_warn("%s family %s IF %s(%u) - no DST", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex); + return 0; + } + memset(&mac, 0, sizeof(struct ethaddr)); + memset(&ip, 0, sizeof(struct ipaddr)); + ip.ipa_type = (ndm->ndm_family == AF_INET) ? IPADDR_V4 : IPADDR_V6; + memcpy(&ip.ip.addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST])); + + if (h->nlmsg_type == RTM_NEWNEIGH) { + if (tb[NDA_LLADDR]) { + if (RTA_PAYLOAD(tb[NDA_LLADDR]) != ETHER_ADDR_LEN) { + zlog_warn( + "%s family %s IF %s(%u) - LLADDR is not MAC, len %ld", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), + ifp->name, ndm->ndm_ifindex, + RTA_PAYLOAD(tb[NDA_LLADDR])); + return 0; + } + + mac_present = 1; + memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), ETHER_ADDR_LEN); + } + + ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "Rx %s family %s IF %s(%u) IP %s MAC %s state 0x%x flags 0x%x", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + ipaddr2str(&ip, buf2, sizeof(buf2)), + mac_present + ? prefix_mac2str(&mac, buf, sizeof(buf)) + : "", + ndm->ndm_state, ndm->ndm_flags); + + /* If the neighbor state is valid for use, process as an add or + * update + * else process as a delete. Note that the delete handling may + * result + * in re-adding the neighbor if it is a valid "remote" neighbor. + */ + if (ndm->ndm_state & NUD_VALID) + return zebra_vxlan_local_neigh_add_update( + ifp, link_if, &ip, &mac, ndm->ndm_state, + ext_learned); + + return zebra_vxlan_local_neigh_del(ifp, link_if, &ip); + } + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Rx %s family %s IF %s(%u) IP %s", + nl_msg_type_to_str(h->nlmsg_type), + nl_family_to_str(ndm->ndm_family), ifp->name, + ndm->ndm_ifindex, + ipaddr2str(&ip, buf2, sizeof(buf2))); + + /* Process the delete - it may result in re-adding the neighbor if it is + * a valid "remote" neighbor. + */ + return zebra_vxlan_local_neigh_del(ifp, link_if, &ip); } -static int -netlink_neigh_table (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id, int startup) +static int netlink_neigh_table(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id, int startup) { - int len; - struct ndmsg *ndm; + int len; + struct ndmsg *ndm; - if (h->nlmsg_type != RTM_NEWNEIGH) - return 0; + if (h->nlmsg_type != RTM_NEWNEIGH) + return 0; - /* Length validity. */ - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); - if (len < 0) - return -1; + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg)); + if (len < 0) + return -1; - /* We are interested only in AF_INET or AF_INET6 notifications. */ - ndm = NLMSG_DATA (h); - if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6) - return 0; + /* We are interested only in AF_INET or AF_INET6 notifications. */ + ndm = NLMSG_DATA(h); + if (ndm->ndm_family != AF_INET && ndm->ndm_family != AF_INET6) + return 0; - return netlink_neigh_change (snl, h, len); + return netlink_neigh_change(snl, h, len); } /* Request for IP neighbor information from the kernel */ -static int -netlink_request_neigh (struct zebra_ns *zns, int family, int type, - ifindex_t ifindex) +static int netlink_request_neigh(struct zebra_ns *zns, int family, int type, + ifindex_t ifindex) { - struct - { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - - /* Form the request, specifying filter (rtattr) if needed. */ - memset (&req, 0, sizeof (req)); - req.n.nlmsg_type = type; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); - req.ndm.ndm_family = family; - if (ifindex) - addattr32 (&req.n, sizeof(req), NDA_IFINDEX, ifindex); - - return netlink_request (&zns->netlink_cmd, &req.n); + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + + /* Form the request, specifying filter (rtattr) if needed. */ + memset(&req, 0, sizeof(req)); + req.n.nlmsg_type = type; + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); + req.ndm.ndm_family = family; + if (ifindex) + addattr32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); + + return netlink_request(&zns->netlink_cmd, &req.n); } /* * IP Neighbor table read using netlink interface. This is invoked * at startup. */ -int -netlink_neigh_read (struct zebra_ns *zns) +int netlink_neigh_read(struct zebra_ns *zns) { - int ret; + int ret; - /* Get IP neighbor table. */ - ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, 0); - if (ret < 0) - return ret; - ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 1); + /* Get IP neighbor table. */ + ret = netlink_request_neigh(zns, AF_UNSPEC, RTM_GETNEIGH, 0); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd, zns, 0, + 1); - return ret; + return ret; } /* * IP Neighbor table read using netlink interface. This is for a specific * VLAN device. */ -int -netlink_neigh_read_for_vlan (struct zebra_ns *zns, struct interface *vlan_if) +int netlink_neigh_read_for_vlan(struct zebra_ns *zns, struct interface *vlan_if) { - int ret = 0; + int ret = 0; - ret = netlink_request_neigh (zns, AF_UNSPEC, RTM_GETNEIGH, vlan_if->ifindex); - if (ret < 0) - return ret; - ret = netlink_parse_info (netlink_neigh_table, &zns->netlink_cmd, zns, 0, 0); + ret = netlink_request_neigh(zns, AF_UNSPEC, RTM_GETNEIGH, + vlan_if->ifindex); + if (ret < 0) + return ret; + ret = netlink_parse_info(netlink_neigh_table, &zns->netlink_cmd, zns, 0, + 0); - return ret; + return ret; } -int -netlink_neigh_change (struct sockaddr_nl *snl, struct nlmsghdr *h, - ns_id_t ns_id) +int netlink_neigh_change(struct sockaddr_nl *snl, struct nlmsghdr *h, + ns_id_t ns_id) { - int len; - struct ndmsg *ndm; + int len; + struct ndmsg *ndm; - if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH)) - return 0; + if (!(h->nlmsg_type == RTM_NEWNEIGH || h->nlmsg_type == RTM_DELNEIGH)) + return 0; - /* Length validity. */ - len = h->nlmsg_len - NLMSG_LENGTH (sizeof (struct ndmsg)); - if (len < 0) - return -1; + /* Length validity. */ + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ndmsg)); + if (len < 0) + return -1; - /* Is this a notification for the MAC FDB or IP neighbor table? */ - ndm = NLMSG_DATA (h); - if (ndm->ndm_family == AF_BRIDGE) - return netlink_macfdb_change (snl, h, len); + /* Is this a notification for the MAC FDB or IP neighbor table? */ + ndm = NLMSG_DATA(h); + if (ndm->ndm_family == AF_BRIDGE) + return netlink_macfdb_change(snl, h, len); - if (ndm->ndm_type != RTN_UNICAST) - return 0; + if (ndm->ndm_type != RTN_UNICAST) + return 0; - if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6) - return netlink_ipneigh_change (snl, h, len); + if (ndm->ndm_family == AF_INET || ndm->ndm_family == AF_INET6) + return netlink_ipneigh_change(snl, h, len); - return 0; + return 0; } -static int -netlink_neigh_update2 (struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, u_int32_t flags, int cmd) +static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac, u_int32_t flags, int cmd) { - struct { - struct nlmsghdr n; - struct ndmsg ndm; - char buf[256]; - } req; - int ipa_len; - - struct zebra_ns *zns = zebra_ns_lookup (NS_DEFAULT); - char buf[INET6_ADDRSTRLEN]; - char buf2[ETHER_ADDR_STRLEN]; - - 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; - if (cmd == RTM_NEWNEIGH) - req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); - req.n.nlmsg_type = cmd; //RTM_NEWNEIGH or RTM_DELNEIGH - req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; - req.ndm.ndm_state = flags; - req.ndm.ndm_ifindex = ifp->ifindex; - req.ndm.ndm_type = RTN_UNICAST; - req.ndm.ndm_flags = NTF_EXT_LEARNED; - - - ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; - addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); - if (mac) - addattr_l (&req.n, sizeof (req), NDA_LLADDR, mac, 6); - - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug ("Tx %s family %s IF %s(%u) Neigh %s MAC %s", - nl_msg_type_to_str (cmd), - nl_family_to_str (req.ndm.ndm_family), - ifp->name, ifp->ifindex, - ipaddr2str (ip, buf, sizeof(buf)), - mac ? prefix_mac2str (mac, buf2, sizeof (buf2)) : "null"); - - return netlink_talk (netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); + struct { + struct nlmsghdr n; + struct ndmsg ndm; + char buf[256]; + } req; + int ipa_len; + + struct zebra_ns *zns = zebra_ns_lookup(NS_DEFAULT); + char buf[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; + + 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; + if (cmd == RTM_NEWNEIGH) + req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); + req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH + req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; + req.ndm.ndm_state = flags; + req.ndm.ndm_ifindex = ifp->ifindex; + req.ndm.ndm_type = RTN_UNICAST; + req.ndm.ndm_flags = NTF_EXT_LEARNED; + + + ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; + addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + if (mac) + addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s", + nl_msg_type_to_str(cmd), + nl_family_to_str(req.ndm.ndm_family), ifp->name, + ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), + mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) + : "null"); + + return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, + 0); } -int -kernel_add_mac (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip, - u_char sticky) +int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, + struct in_addr vtep_ip, u_char sticky) { - return netlink_macfdb_update (ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH, sticky); + return netlink_macfdb_update(ifp, vid, mac, vtep_ip, 0, RTM_NEWNEIGH, + sticky); } -int -kernel_del_mac (struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip, int local) +int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, + struct in_addr vtep_ip, int local) { - return netlink_macfdb_update (ifp, vid, mac, vtep_ip, local, RTM_DELNEIGH, 0); + return netlink_macfdb_update(ifp, vid, mac, vtep_ip, local, + RTM_DELNEIGH, 0); } -int kernel_add_neigh (struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac) +int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, + struct ethaddr *mac) { - return netlink_neigh_update2 (ifp, ip, mac, NUD_REACHABLE, - RTM_NEWNEIGH); + return netlink_neigh_update2(ifp, ip, mac, NUD_REACHABLE, RTM_NEWNEIGH); } -int kernel_del_neigh (struct interface *ifp, struct ipaddr *ip) +int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) { - return netlink_neigh_update2 (ifp, ip, NULL, 0, RTM_DELNEIGH); + return netlink_neigh_update2(ifp, ip, NULL, 0, RTM_DELNEIGH); } /* * 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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; - - 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.n.nlmsg_pid = zns->netlink_cmd.snl.nl_pid; + + 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); + } } |
