diff options
Diffstat (limited to 'zebra/rt_netlink.c')
| -rw-r--r-- | zebra/rt_netlink.c | 332 |
1 files changed, 182 insertions, 150 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 95ac68fb90..91a3024038 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -92,6 +92,41 @@ void rt_netlink_init(void) inet_pton(AF_INET, ipv4_ll_buf, &ipv4_ll); } +/* + * Mapping from dataplane neighbor flags to netlink flags + */ +static uint8_t neigh_flags_to_netlink(uint8_t dplane_flags) +{ + uint8_t flags = 0; + + if (dplane_flags & DPLANE_NTF_EXT_LEARNED) + flags |= NTF_EXT_LEARNED; + if (dplane_flags & DPLANE_NTF_ROUTER) + flags |= NTF_ROUTER; + + return flags; +} + +/* + * Mapping from dataplane neighbor state to netlink state + */ +static uint16_t neigh_state_to_netlink(uint16_t dplane_state) +{ + uint16_t state = 0; + + if (dplane_state & DPLANE_NUD_REACHABLE) + state |= NUD_REACHABLE; + if (dplane_state & DPLANE_NUD_STALE) + state |= NUD_STALE; + if (dplane_state & DPLANE_NUD_NOARP) + state |= NUD_NOARP; + if (dplane_state & DPLANE_NUD_PROBE) + state |= NUD_PROBE; + + return state; +} + + static inline int is_selfroute(int proto) { if ((proto == RTPROT_BGP) || (proto == RTPROT_OSPF) @@ -1019,33 +1054,28 @@ static void _netlink_route_build_singlepath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { - char label_buf1[20]; + char label_buf1[20]; - nh_label = nh->nh_label; - if (!nh_label || !nh_label->num_labels) - continue; + nh_label = nexthop->nh_label; - for (int i = 0; i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; + for (int i = 0; nh_label && i < nh_label->num_labels; i++) { + if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) + continue; - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", - nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!num_labels) + sprintf(label_buf, "label %u", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%u", nh_label->label[i]); + strlcat(label_buf, label_buf1, + sizeof(label_buf)); } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; } + + out_lse[num_labels] = + mpls_lse_encode(nh_label->label[i], 0, 0, 0); + num_labels++; } if (num_labels) { @@ -1210,33 +1240,28 @@ static void _netlink_route_build_multipath(const char *routedesc, int bytelen, label_buf[0] = '\0'; assert(nexthop); - for (const struct nexthop *nh = nexthop; nh; nh = nh->rparent) { - char label_buf1[20]; + char label_buf1[20]; - nh_label = nh->nh_label; - if (!nh_label || !nh_label->num_labels) - continue; + nh_label = nexthop->nh_label; - for (int i = 0; i < nh_label->num_labels; i++) { - if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) - continue; + for (int i = 0; nh_label && i < nh_label->num_labels; i++) { + if (nh_label->label[i] == MPLS_LABEL_IMPLICIT_NULL) + continue; - if (IS_ZEBRA_DEBUG_KERNEL) { - if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); - else { - sprintf(label_buf1, "/%u", - nh_label->label[i]); - strlcat(label_buf, label_buf1, - sizeof(label_buf)); - } + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!num_labels) + sprintf(label_buf, "label %u", + nh_label->label[i]); + else { + sprintf(label_buf1, "/%u", nh_label->label[i]); + strlcat(label_buf, label_buf1, + sizeof(label_buf)); } - - out_lse[num_labels] = - mpls_lse_encode(nh_label->label[i], 0, 0, 0); - num_labels++; } + + out_lse[num_labels] = + mpls_lse_encode(nh_label->label[i], 0, 0, 0); + num_labels++; } if (num_labels) { @@ -1902,19 +1927,17 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, * 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_update_ctx(const struct zebra_dplane_ctx *ctx, + int cmd) { - struct zebra_ns *zns; struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; uint8_t dst_mac[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + const struct ipaddr *addr; - zns = zvrf->zns; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); @@ -1928,39 +1951,14 @@ static int netlink_vxlan_flood_list_update(struct interface *ifp, 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); + req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); - 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 - * a "flood" MAC FDB entry. - */ -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); + addr = dplane_ctx_neigh_get_ipaddr(ctx); - return netlink_vxlan_flood_list_update(ifp, vtep_ip, RTM_NEWNEIGH); -} + addattr_l(&req.n, sizeof(req), NDA_DST, &(addr->ipaddr_v4), 4); -/* - * 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) -{ - 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_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); } #ifndef NDA_RTA @@ -2292,34 +2290,29 @@ int netlink_macfdb_read_specific_mac(struct zebra_ns *zns, return ret; } -static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, - struct ethaddr *mac, struct in_addr vtep_ip, - int cmd, bool sticky) + +/* + * Netlink-specific handler for MAC updates using dataplane context object. + */ +static enum zebra_dplane_result +netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx) { - struct zebra_ns *zns; struct { struct nlmsghdr n; struct ndmsg ndm; char buf[256]; } req; + int ret; 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; - char vid_buf[20]; - char dst_buf[30]; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + int cmd; + struct in_addr vtep_ip; + vlanid_t vid; - zns = zvrf->zns; - zif = ifp->info; - if ((br_if = zif->brslave_info.br_if) == NULL) { - zlog_debug("MAC %s on IF %s(%u) - no mapping to bridge", - (cmd == RTM_NEWNEIGH) ? "add" : "del", ifp->name, - ifp->ifindex); - return -1; - } + if (dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL) + cmd = RTM_NEWNEIGH; + else + cmd = RTM_DELNEIGH; memset(&req, 0, sizeof(req)); @@ -2332,34 +2325,58 @@ static int netlink_macfdb_update(struct interface *ifp, vlanid_t vid, req.ndm.ndm_flags |= NTF_SELF | NTF_MASTER; req.ndm.ndm_state = NUD_REACHABLE; - if (sticky) + if (dplane_ctx_mac_is_sticky(ctx)) 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; + addattr_l(&req.n, sizeof(req), NDA_LLADDR, + dplane_ctx_mac_get_addr(ctx), 6); + req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); + dst_alen = 4; // TODO: hardcoded + vtep_ip = *(dplane_ctx_mac_get_vtep_ip(ctx)); addattr_l(&req.n, sizeof(req), NDA_DST, &vtep_ip, dst_alen); - 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) { + + vid = dplane_ctx_mac_get_vlan(ctx); + + if (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); + addattr32(&req.n, sizeof(req), NDA_MASTER, + dplane_ctx_mac_get_br_ifindex(ctx)); + + if (IS_ZEBRA_DEBUG_KERNEL) { + char ipbuf[PREFIX_STRLEN]; + char buf[ETHER_ADDR_STRLEN]; + char dst_buf[PREFIX_STRLEN + 10]; + char vid_buf[20]; + + if (vid_present) + snprintf(vid_buf, sizeof(vid_buf), " VLAN %u", vid); + else + vid_buf[0] = '\0'; + + inet_ntop(AF_INET, &vtep_ip, ipbuf, sizeof(ipbuf)); + snprintf(dst_buf, sizeof(dst_buf), " dst %s", ipbuf); + prefix_mac2str(dplane_ctx_mac_get_addr(ctx), buf, sizeof(buf)); - 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_buf); + nl_family_to_str(req.ndm.ndm_family), + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx), vid_buf, + dplane_ctx_mac_is_sticky(ctx) ? "sticky " : "", + buf, dst_buf); + } - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - 0); + ret = netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); + if (ret == 0) + return ZEBRA_DPLANE_REQUEST_SUCCESS; + else + return ZEBRA_DPLANE_REQUEST_FAILURE; } /* @@ -2725,9 +2742,11 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) return 0; } -static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, uint8_t flags, - uint16_t state, int cmd) +/* + * Utility neighbor-update function, using info from dplane context. + */ +static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, + int cmd) { struct { struct nlmsghdr n; @@ -2735,15 +2754,23 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, char buf[256]; } req; int ipa_len; - - struct zebra_ns *zns; char buf[INET6_ADDRSTRLEN]; char buf2[ETHER_ADDR_STRLEN]; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + const struct ipaddr *ip; + const struct ethaddr *mac; + uint8_t flags; + uint16_t state; - zns = zvrf->zns; memset(&req, 0, sizeof(req)); + ip = dplane_ctx_neigh_get_ipaddr(ctx); + mac = dplane_ctx_neigh_get_mac(ctx); + if (is_zero_mac(mac)) + mac = NULL; + + flags = neigh_flags_to_netlink(dplane_ctx_neigh_get_flags(ctx)); + state = neigh_state_to_netlink(dplane_ctx_neigh_get_state(ctx)); + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; if (cmd == RTM_NEWNEIGH) @@ -2751,7 +2778,7 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, 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 = state; - req.ndm.ndm_ifindex = ifp->ifindex; + req.ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); req.ndm.ndm_type = RTN_UNICAST; req.ndm.ndm_flags = flags; @@ -2763,45 +2790,50 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x state 0x%x", nl_msg_type_to_str(cmd), - nl_family_to_str(req.ndm.ndm_family), ifp->name, - ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), + nl_family_to_str(req.ndm.ndm_family), + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_ifindex(ctx), + ipaddr2str(ip, buf, sizeof(buf)), mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null", flags, state); + : "null", + flags, state); - return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, - 0); + return netlink_talk_info(netlink_talk_filter, &req.n, + dplane_ctx_get_ns(ctx), 0); } -int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip, bool sticky) +/* + * Update MAC, using dataplane context object. + */ +enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) { - return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_NEWNEIGH, - sticky); + return netlink_macfdb_update_ctx(ctx); } -int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip) +enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx) { - return netlink_macfdb_update(ifp, vid, mac, vtep_ip, RTM_DELNEIGH, 0); -} + int ret = -1; -int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, uint8_t flags) -{ - return netlink_neigh_update2(ifp, ip, mac, flags, - NUD_NOARP, RTM_NEWNEIGH); -} - -int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) -{ - return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH); -} + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + ret = netlink_neigh_update_ctx(ctx, RTM_NEWNEIGH); + break; + case DPLANE_OP_NEIGH_DELETE: + ret = netlink_neigh_update_ctx(ctx, RTM_DELNEIGH); + break; + case DPLANE_OP_VTEP_ADD: + ret = netlink_vxlan_flood_update_ctx(ctx, RTM_NEWNEIGH); + break; + case DPLANE_OP_VTEP_DELETE: + ret = netlink_vxlan_flood_update_ctx(ctx, RTM_DELNEIGH); + break; + default: + break; + } -int kernel_upd_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, uint8_t flags, uint16_t state) -{ - return netlink_neigh_update2(ifp, ip, mac, flags, - state, RTM_NEWNEIGH); + return (ret == 0 ? + ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE); } /* |
