diff options
author | Philippe Guibert <philippe.guibert@6wind.com> | 2019-12-13 18:09:11 +0100 |
---|---|---|
committer | Philippe Guibert <philippe.guibert@6wind.com> | 2021-04-09 18:29:58 +0200 |
commit | 05657ec2b78911e4b7bae3692fa27cd81945ad73 (patch) | |
tree | 49c6ae5fbc886b79cbbd0a4fbfa8c63659d870c0 | |
parent | nhrpd: link layer registration to notifications (diff) | |
download | frr-05657ec2b78911e4b7bae3692fa27cd81945ad73.tar.xz frr-05657ec2b78911e4b7bae3692fa27cd81945ad73.zip |
nhrp, lib, zebra: add/del neighbor entry possible from nhrp
a zebra api is extended to offer ability to add or remove neighbor
entry from daemon. Also this extension makes possible to add neigh
entry, not only between IPs and macs, but also between IPs and NBMA IPs.
This API supports configuring ipv6/ipv4 entries with ipv4/ipv6 lladdr.
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r-- | lib/log.c | 4 | ||||
-rw-r--r-- | lib/zclient.h | 13 | ||||
-rw-r--r-- | nhrpd/netlink_arp.c | 23 | ||||
-rw-r--r-- | nhrpd/nhrp_route.c | 26 | ||||
-rw-r--r-- | nhrpd/nhrpd.h | 3 | ||||
-rw-r--r-- | zebra/interface.c | 7 | ||||
-rw-r--r-- | zebra/rt.h | 5 | ||||
-rw-r--r-- | zebra/rt_netlink.c | 29 | ||||
-rw-r--r-- | zebra/rt_socket.c | 4 | ||||
-rw-r--r-- | zebra/zapi_msg.c | 80 |
10 files changed, 154 insertions, 40 deletions
@@ -469,7 +469,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_NHRP_NEIGH_REMOVED), DESC_ENTRY(ZEBRA_NHRP_NEIGH_GET), DESC_ENTRY(ZEBRA_NHRP_NEIGH_REGISTER), - DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER)}; + DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER), + DESC_ENTRY(ZEBRA_NEIGH_ADD), + DESC_ENTRY(ZEBRA_NEIGH_DEL)}; #undef DESC_ENTRY diff --git a/lib/zclient.h b/lib/zclient.h index d0d77f93c..8d531c53f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -228,6 +228,8 @@ typedef enum { ZEBRA_NHRP_NEIGH_GET, ZEBRA_NHRP_NEIGH_REGISTER, ZEBRA_NHRP_NEIGH_UNREGISTER, + ZEBRA_NEIGH_ADD, + ZEBRA_NEIGH_DEL, } zebra_message_types_t; enum zebra_error_types { @@ -802,6 +804,17 @@ struct zclient_options { extern struct zclient_options zclient_options_default; +/* link layer representation for GRE like interfaces + * pfx_in is the underlay IP, pfx_out is the tunnel dest + * index stands for the index of the interface + */ +struct zapi_nbr { + int cmd; + struct prefix pfx_in; + struct prefix pfx_out; + ifindex_t index; +}; + /* * We reserve the top 4 bits for l2-NHG, everything else * is for zebra/proto l3-NHG. diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index bb8e73ab1..bf5d74c25 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -34,28 +34,7 @@ typedef void (*netlink_dispatch_f)(struct nlmsghdr *msg, struct zbuf *zb); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma) { - struct nlmsghdr *n; - struct ndmsg *ndm; - struct zbuf *zb = zbuf_alloc(512); - - n = znl_nlmsg_push(zb, nbma ? RTM_NEWNEIGH : RTM_DELNEIGH, - NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE); - ndm = znl_push(zb, sizeof(*ndm)); - *ndm = (struct ndmsg){ - .ndm_family = sockunion_family(proto), - .ndm_ifindex = ifp->ifindex, - .ndm_type = RTN_UNICAST, - .ndm_state = nbma ? NUD_REACHABLE : NUD_FAILED, - }; - znl_rta_push(zb, NDA_DST, sockunion_get_addr(proto), - family2addrsize(sockunion_family(proto))); - if (nbma) - znl_rta_push(zb, NDA_LLADDR, sockunion_get_addr(nbma), - family2addrsize(sockunion_family(nbma))); - znl_nlmsg_complete(zb, n); - zbuf_send(zb, netlink_req_fd); - zbuf_recv(zb, netlink_req_fd); - zbuf_free(zb); + nhrp_send_zebra_nbr(proto, nbma, ifp); } static void netlink_log_register(int fd, int group) diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 746b585ed..06a9564e8 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -392,6 +392,32 @@ static void nhrp_table_node_cleanup(struct route_table *table, XFREE(MTYPE_NHRP_ROUTE, node->info); } +void nhrp_send_zebra_nbr(union sockunion *in, + union sockunion *out, + struct interface *ifp) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) + return; + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, + out ? ZEBRA_NEIGH_ADD : ZEBRA_NEIGH_DEL, + ifp->vrf_id); + stream_putc(s, sockunion_family(in)); + stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in)); + if (out) { + stream_putc(s, sockunion_family(out)); + stream_write(s, sockunion_get_addr(out), + sockunion_get_addrlen(out)); + } + stream_putl(s, ifp->ifindex); + + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} + void nhrp_zebra_terminate(void) { nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 6e7ddda18..0f4635d3d 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -88,6 +88,9 @@ static inline int notifier_active(struct notifier_list *l) void nhrp_zebra_init(void); void nhrp_zebra_terminate(void); +void nhrp_send_zebra_nbr(union sockunion *in, + union sockunion *out, + struct interface *ifp); struct zbuf; struct nhrp_vc; diff --git a/zebra/interface.c b/zebra/interface.c index 3eeed9ac9..4b708496a 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -898,7 +898,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp, * Remove and re-add any existing neighbor entry for this address, * since Netlink doesn't currently offer update message types. */ - kernel_neigh_update(0, ifp->ifindex, ipv4_ll.s_addr, mac, 6, ns_id); + kernel_neigh_update(0, ifp->ifindex, (void *)&ipv4_ll.s_addr, mac, 6, + ns_id, AF_INET, true); /* Add new neighbor entry. * @@ -910,8 +911,8 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp, * they'll be useless to us. */ if (add) - kernel_neigh_update(add, ifp->ifindex, ipv4_ll.s_addr, mac, 6, - ns_id); + kernel_neigh_update(add, ifp->ifindex, (void *)&ipv4_ll.s_addr, + mac, 6, ns_id, AF_INET, true); memcpy(&zif->neigh_mac[0], &mac[0], 6); diff --git a/zebra/rt.h b/zebra/rt.h index 00ff37875..f79ddbe95 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -68,8 +68,9 @@ kernel_pbr_rule_update(struct zebra_dplane_ctx *ctx); #endif /* !HAVE_NETLINK */ -extern int kernel_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id); +extern int kernel_neigh_update(int cmd, int ifindex, void *addr, char *lla, + int llalen, ns_id_t ns_id, uint8_t family, + bool permanent); extern int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg); extern int kernel_interface_set_master(struct interface *master, diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 82ef78d29..be9c91367 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1537,10 +1537,10 @@ static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) routedesc, nl_msg_type_to_str(cmd), label); } -static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla, + int llalen, ns_id_t ns_id, uint8_t family, + bool permanent, uint8_t protocol) { - uint8_t protocol = RTPROT_ZEBRA; struct { struct nlmsghdr n; struct ndmsg ndm; @@ -1556,15 +1556,23 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, 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_family = family; req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; + if (cmd == RTM_NEWNEIGH) { + if (!permanent) + req.ndm.ndm_state = NUD_REACHABLE; + else + req.ndm.ndm_state = NUD_PERMANENT; + } else + req.ndm.ndm_state = NUD_FAILED; nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol, sizeof(protocol)); - nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr); - nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + req.ndm.ndm_type = RTN_UNICAST; + nl_attr_put32(&req.n, family2addrsize(family), NDA_DST, addr); + if (lla) + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2679,11 +2687,12 @@ int netlink_nexthop_read(struct zebra_ns *zns) } -int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen, + ns_id_t ns_id, uint8_t family, bool permanent) { return netlink_neigh_update(add ? RTM_NEWNEIGH : RTM_DELNEIGH, ifindex, - addr, lla, llalen, ns_id); + addr, lla, llalen, ns_id, family, permanent, + RTPROT_ZEBRA); } /** diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 5fdf58962..006513ac9 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -368,8 +368,8 @@ int kernel_neigh_register(vrf_id_t vrf_id, struct zserv *client, bool reg) return 0; } -int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, - int llalen, ns_id_t ns_id) +int kernel_neigh_update(int add, int ifindex, void *addr, char *lla, int llalen, + ns_id_t ns_id, uint8_t family, bool permanent) { /* TODO */ return 0; diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 304a6a03f..909b3b8ac 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3214,6 +3214,39 @@ stream_failure: return; } +static int zebra_neigh_read_ip(struct stream *s, struct prefix *add) +{ + STREAM_GETC(s, add->family); + if (add->family != AF_INET && add->family != AF_INET6) + return -1; + STREAM_GET(&add->u.prefix, s, family2addrsize(add->family)); + if (add->family == AF_INET) + add->prefixlen = IPV4_MAX_BITLEN; + else + add->prefixlen = IPV6_MAX_BITLEN; + return 0; +stream_failure: + return -1; +} + +static int zebra_neigh_get(struct stream *s, struct zapi_nbr *api, bool add) +{ + int ret; + + ret = zebra_neigh_read_ip(s, &api->pfx_in); + if (ret < 0) + return -1; + if (add) { + ret = zebra_neigh_read_ip(s, &api->pfx_out); + if (ret < 0) + return -1; + } + STREAM_GETL(s, api->index); + return 0; +stream_failure: + return -1; +} + static inline void zebra_neigh_register(ZAPI_HANDLER_ARGS) { afi_t afi; @@ -3246,6 +3279,51 @@ stream_failure: return; } +static inline void zebra_neigh_add(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_nbr api; + int ret; + struct zebra_ns *zns = zvrf->zns; + ns_id_t ns_id; + + if (!zns) + return; + ns_id = zns->ns_id; + + s = msg; + memset(&api, 0, sizeof(api)); + ret = zebra_neigh_get(s, &api, true); + if (ret < 0) + return; + kernel_neigh_update(1, api.index, &api.pfx_in.u.prefix, + (char *)&api.pfx_out.u.prefix, + family2addrsize(api.pfx_out.family), + ns_id, api.pfx_in.family, false, client->proto); +} + +static inline void zebra_neigh_del(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + struct zapi_nbr api; + int ret; + struct zebra_ns *zns = zvrf->zns; + ns_id_t ns_id; + + if (!zns) + return; + ns_id = zns->ns_id; + s = msg; + memset(&api, 0, sizeof(api)); + ret = zebra_neigh_get(s, &api, false); + if (ret < 0) + return; + kernel_neigh_update(0, api.index, &api.pfx_in.u.prefix, + NULL, 0, ns_id, api.pfx_in.family, + true, client->proto); +} + + static inline void zread_iptable(ZAPI_HANDLER_ARGS) { struct zebra_pbr_iptable *zpi = @@ -3431,6 +3509,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_ROUTE_NOTIFY_REQUEST] = zread_route_notify_request, [ZEBRA_EVPN_REMOTE_NH_ADD] = zebra_evpn_proc_remote_nh, [ZEBRA_EVPN_REMOTE_NH_DEL] = zebra_evpn_proc_remote_nh, + [ZEBRA_NEIGH_ADD] = zebra_neigh_add, + [ZEBRA_NEIGH_DEL] = zebra_neigh_del, [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register, [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister, }; |