diff options
-rw-r--r-- | include/linux/if_packet.h | 16 | ||||
-rw-r--r-- | include/linux/if_tunnel.h | 71 | ||||
-rw-r--r-- | lib/log.c | 5 | ||||
-rw-r--r-- | lib/zclient.c | 25 | ||||
-rw-r--r-- | lib/zclient.h | 6 | ||||
-rw-r--r-- | nhrpd/linux.c | 22 | ||||
-rw-r--r-- | nhrpd/netlink.h | 11 | ||||
-rw-r--r-- | nhrpd/netlink_arp.c | 8 | ||||
-rw-r--r-- | nhrpd/netlink_gre.c | 152 | ||||
-rw-r--r-- | nhrpd/nhrp_interface.c | 93 | ||||
-rw-r--r-- | nhrpd/nhrp_main.c | 2 | ||||
-rw-r--r-- | nhrpd/nhrp_route.c | 78 | ||||
-rw-r--r-- | nhrpd/nhrpd.h | 33 | ||||
-rw-r--r-- | nhrpd/subdir.am | 1 | ||||
-rw-r--r-- | zebra/debug.c | 2 | ||||
-rw-r--r-- | zebra/if_netlink.c | 145 | ||||
-rw-r--r-- | zebra/if_netlink.h | 3 | ||||
-rw-r--r-- | zebra/interface.c | 31 | ||||
-rw-r--r-- | zebra/interface.h | 4 | ||||
-rw-r--r-- | zebra/kernel_netlink.c | 3 | ||||
-rw-r--r-- | zebra/rt.h | 3 | ||||
-rw-r--r-- | zebra/rt_socket.c | 6 | ||||
-rw-r--r-- | zebra/zapi_msg.c | 108 | ||||
-rw-r--r-- | zebra/zebra_dplane.c | 125 | ||||
-rw-r--r-- | zebra/zebra_dplane.h | 16 | ||||
-rw-r--r-- | zebra/zebra_errors.h | 1 | ||||
-rw-r--r-- | zebra/zebra_l2.c | 26 | ||||
-rw-r--r-- | zebra/zebra_l2.h | 17 | ||||
-rw-r--r-- | zebra/zebra_nhg.c | 1 | ||||
-rw-r--r-- | zebra/zebra_rib.c | 1 |
30 files changed, 788 insertions, 227 deletions
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h new file mode 100644 index 000000000..057edb33d --- /dev/null +++ b/include/linux/if_packet.h @@ -0,0 +1,16 @@ +#ifndef __LINUX_IF_PACKET_H +#define __LINUX_IF_PACKET_H + +#include <linux/types.h> + +struct sockaddr_ll { + unsigned short sll_family; + __be16 sll_protocol; + int sll_ifindex; + unsigned short sll_hatype; + unsigned char sll_pkttype; + unsigned char sll_halen; + unsigned char sll_addr[8]; +}; + +#endif diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h new file mode 100644 index 000000000..982a1b60d --- /dev/null +++ b/include/linux/if_tunnel.h @@ -0,0 +1,71 @@ +#ifndef _IF_TUNNEL_H_ +#define _IF_TUNNEL_H_ + +#include <linux/types.h> +#include <linux/if.h> +#include <linux/ip.h> +#include <linux/in6.h> +#include <asm/byteorder.h> + + +#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0) +#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) +#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) +#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +#define SIOCGETPRL (SIOCDEVPRIVATE + 4) +#define SIOCADDPRL (SIOCDEVPRIVATE + 5) +#define SIOCDELPRL (SIOCDEVPRIVATE + 6) +#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) + +#define GRE_CSUM __cpu_to_be16(0x8000) +#define GRE_ROUTING __cpu_to_be16(0x4000) +#define GRE_KEY __cpu_to_be16(0x2000) +#define GRE_SEQ __cpu_to_be16(0x1000) +#define GRE_STRICT __cpu_to_be16(0x0800) +#define GRE_REC __cpu_to_be16(0x0700) +#define GRE_FLAGS __cpu_to_be16(0x00F8) +#define GRE_VERSION __cpu_to_be16(0x0007) + +struct ip_tunnel_parm { + char name[IFNAMSIZ]; + int link; + __be16 i_flags; + __be16 o_flags; + __be32 i_key; + __be32 o_key; + struct iphdr iph; +}; + +/* SIT-mode i_flags */ +#define SIT_ISATAP 0x0001 + +struct ip_tunnel_prl { + __be32 addr; + __u16 flags; + __u16 __reserved; + __u32 datalen; + __u32 __reserved2; + /* data follows */ +}; + +/* PRL flags */ +#define PRL_DEFAULT 0x0001 + +enum { + IFLA_GRE_UNSPEC, + IFLA_GRE_LINK, + IFLA_GRE_IFLAGS, + IFLA_GRE_OFLAGS, + IFLA_GRE_IKEY, + IFLA_GRE_OKEY, + IFLA_GRE_LOCAL, + IFLA_GRE_REMOTE, + IFLA_GRE_TTL, + IFLA_GRE_TOS, + IFLA_GRE_PMTUDISC, + __IFLA_GRE_MAX, +}; + +#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1) + +#endif /* _IF_TUNNEL_H_ */ @@ -461,7 +461,10 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_NHRP_NEIGH_UNREGISTER), DESC_ENTRY(ZEBRA_NEIGH_IP_ADD), DESC_ENTRY(ZEBRA_NEIGH_IP_DEL), - DESC_ENTRY(ZEBRA_CONFIGURE_ARP)}; + DESC_ENTRY(ZEBRA_CONFIGURE_ARP), + DESC_ENTRY(ZEBRA_GRE_GET), + DESC_ENTRY(ZEBRA_GRE_UPDATE), + DESC_ENTRY(ZEBRA_GRE_SOURCE_SET)}; #undef DESC_ENTRY static const struct zebra_desc_table unknown = {0, "unknown", '?'}; diff --git a/lib/zclient.c b/lib/zclient.c index b1aea55af..3ea178944 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -3931,6 +3931,11 @@ static int zclient_read(struct thread *thread) (*zclient->neighbor_get)(command, zclient, length, vrf_id); break; + case ZEBRA_GRE_UPDATE: + if (zclient->gre_update) + (*zclient->gre_update)(command, zclient, + length, vrf_id); + break; default: break; } @@ -4252,3 +4257,23 @@ int zclient_neigh_ip_decode(struct stream *s, struct zapi_neigh_ip *api) stream_failure: return -1; } + +int zclient_send_zebra_gre_request(struct zclient *client, + struct interface *ifp) +{ + struct stream *s; + + if (!client || client->sock < 0) { + zlog_err("%s : zclient not ready", __func__); + return -1; + } + s = client->obuf; + stream_reset(s); + zclient_create_header(s, + ZEBRA_GRE_GET, + ifp->vrf_id); + stream_putl(s, ifp->ifindex); + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(client); + return 0; +} diff --git a/lib/zclient.h b/lib/zclient.h index e8fff4b88..8c2791654 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -232,6 +232,9 @@ typedef enum { ZEBRA_NEIGH_IP_ADD, ZEBRA_NEIGH_IP_DEL, ZEBRA_CONFIGURE_ARP, + ZEBRA_GRE_GET, + ZEBRA_GRE_UPDATE, + ZEBRA_GRE_SOURCE_SET, } zebra_message_types_t; enum zebra_error_types { @@ -393,6 +396,7 @@ struct zclient { void (*neighbor_added)(ZAPI_CALLBACK_ARGS); void (*neighbor_removed)(ZAPI_CALLBACK_ARGS); void (*neighbor_get)(ZAPI_CALLBACK_ARGS); + void (*gre_update)(ZAPI_CALLBACK_ARGS); }; /* Zebra API message flag. */ @@ -1228,6 +1232,8 @@ struct zapi_client_close_info { extern int zapi_client_close_notify_decode(struct stream *s, struct zapi_client_close_info *info); +extern int zclient_send_zebra_gre_request(struct zclient *client, + struct interface *ifp); #ifdef __cplusplus } #endif diff --git a/nhrpd/linux.c b/nhrpd/linux.c index f697311d4..4986bfb99 100644 --- a/nhrpd/linux.c +++ b/nhrpd/linux.c @@ -7,30 +7,12 @@ * (at your option) any later version. */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <fcntl.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> #include <errno.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <asm/types.h> -#include <arpa/inet.h> -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/ip.h> -#include <linux/if_arp.h> -#include <linux/if_tunnel.h> -#include <linux/limits.h> +#include "zebra.h" +#include <linux/if_packet.h> #include "nhrp_protocol.h" #include "os.h" -#include "netlink.h" #ifndef HAVE_STRLCPY size_t strlcpy(char *__restrict dest, diff --git a/nhrpd/netlink.h b/nhrpd/netlink.h index 5e971cabf..f1143a2b5 100644 --- a/nhrpd/netlink.h +++ b/nhrpd/netlink.h @@ -7,21 +7,16 @@ * (at your option) any later version. */ -#include <stdint.h> +#include <zebra.h> +#include <vrf.h> +#include <if.h> -union sockunion; -struct interface; extern int netlink_nflog_group; extern int netlink_mcast_nflog_group; -extern int netlink_req_fd; -void netlink_init(void); int netlink_configure_arp(unsigned int ifindex, int pf); void netlink_update_binding(struct interface *ifp, union sockunion *proto, union sockunion *nbma); void netlink_set_nflog_group(int nlgroup); -void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, - unsigned int *link_index, struct in_addr *saddr); -void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index); diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index ecea0a9ec..5fcb31188 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -25,7 +25,6 @@ #include "netlink.h" #include "znl.h" -int netlink_req_fd = -1; int netlink_nflog_group; static int netlink_log_fd = -1; static struct thread *netlink_log_thread; @@ -203,10 +202,3 @@ void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE); } } - -void netlink_init(void) -{ - netlink_req_fd = znl_open(NETLINK_ROUTE, 0); - if (netlink_req_fd < 0) - return; -} diff --git a/nhrpd/netlink_gre.c b/nhrpd/netlink_gre.c deleted file mode 100644 index 3fdfa9c31..000000000 --- a/nhrpd/netlink_gre.c +++ /dev/null @@ -1,152 +0,0 @@ -/* NHRP netlink/GRE tunnel configuration code - * Copyright (c) 2014-2016 Timo Teräs - * - * This file is free software: you may copy, redistribute and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/socket.h> -#include <linux/netlink.h> -#include <linux/rtnetlink.h> -#include <linux/in.h> -#include <linux/if.h> -#include <linux/ip.h> -#include <linux/ipv6.h> -#include <linux/if_tunnel.h> - -#include "debug.h" -#include "netlink.h" -#include "znl.h" - -static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, - int ifindex) -{ - struct nlmsghdr *n; - struct ifinfomsg *ifi; - struct zbuf payload, rtapayload; - struct rtattr *rta; - - debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex); - - n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST); - ifi = znl_push(zb, sizeof(*ifi)); - *ifi = (struct ifinfomsg){ - .ifi_index = ifindex, - }; - znl_nlmsg_complete(zb, n); - - if (zbuf_send(zb, netlink_req_fd) < 0 - || zbuf_recv(zb, netlink_req_fd) < 0) - return -1; - - n = znl_nlmsg_pull(zb, &payload); - if (!n) - return -1; - - if (n->nlmsg_type != RTM_NEWLINK) - return -1; - - ifi = znl_pull(&payload, sizeof(struct ifinfomsg)); - if (!ifi) - return -1; - - debugf(NHRP_DEBUG_KERNEL, - "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u", - ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags); - - if (ifi->ifi_index != ifindex) - return -1; - - while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) - if (rta->rta_type == IFLA_LINKINFO) - break; - if (!rta) - return -1; - - payload = rtapayload; - while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL) - if (rta->rta_type == IFLA_INFO_DATA) - break; - if (!rta) - return -1; - - *data = rtapayload; - return 0; -} - -void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, - unsigned int *link_index, struct in_addr *saddr) -{ - struct zbuf *zb = zbuf_alloc(8192), data, rtapl; - struct rtattr *rta; - - *link_index = 0; - *gre_key = 0; - saddr->s_addr = 0; - - if (__netlink_gre_get_data(zb, &data, ifindex) < 0) - goto err; - - while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { - switch (rta->rta_type) { - case IFLA_GRE_LINK: - *link_index = zbuf_get32(&rtapl); - break; - case IFLA_GRE_IKEY: - case IFLA_GRE_OKEY: - *gre_key = zbuf_get32(&rtapl); - break; - case IFLA_GRE_LOCAL: - saddr->s_addr = zbuf_get32(&rtapl); - break; - } - } -err: - zbuf_free(zb); -} - -void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index) -{ - struct nlmsghdr *n; - struct ifinfomsg *ifi; - struct rtattr *rta_info, *rta_data, *rta; - struct zbuf *zr = zbuf_alloc(8192), data, rtapl; - struct zbuf *zb = zbuf_alloc(8192); - size_t len; - - if (__netlink_gre_get_data(zr, &data, ifindex) < 0) - goto err; - - n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST); - ifi = znl_push(zb, sizeof(*ifi)); - *ifi = (struct ifinfomsg){ - .ifi_index = ifindex, - }; - rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO); - znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3); - rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA); - - znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index); - while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) { - if (rta->rta_type == IFLA_GRE_LINK) - continue; - len = zbuf_used(&rtapl); - znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len); - } - - znl_rta_nested_complete(zb, rta_data); - znl_rta_nested_complete(zb, rta_info); - - znl_nlmsg_complete(zb, n); - zbuf_send(zb, netlink_req_fd); - zbuf_recv(zb, netlink_req_fd); -err: - zbuf_free(zb); - zbuf_free(zr); -} diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 402ffe9a2..2db8997ba 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -19,14 +19,52 @@ #include "nhrpd.h" #include "os.h" -#include "netlink.h" +#include "hash.h" DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface"); +DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF_GRE, "NHRP GRE interface"); + +struct hash *nhrp_gre_list; static void nhrp_interface_update_cache_config(struct interface *ifp, bool available, uint8_t family); +static unsigned int nhrp_gre_info_key(const void *data) +{ + const struct nhrp_gre_info *r = data; + + return r->ifindex; +} + +static bool nhrp_gre_info_cmp(const void *data, const void *key) +{ + const struct nhrp_gre_info *a = data, *b = key; + + if (a->ifindex == b->ifindex) + return true; + return false; +} + +static void *nhrp_interface_gre_alloc(void *data) +{ + struct nhrp_gre_info *a; + struct nhrp_gre_info *b = data; + + a = XMALLOC(MTYPE_NHRP_IF_GRE, sizeof(struct nhrp_gre_info)); + memcpy(a, b, sizeof(struct nhrp_gre_info)); + return a; +} + +struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p) +{ + struct nhrp_gre_info *a; + + a = (struct nhrp_gre_info *)hash_get(nhrp_gre_list, p, + nhrp_interface_gre_alloc); + return a; +} + static int nhrp_if_new_hook(struct interface *ifp) { struct nhrp_interface *nifp; @@ -74,6 +112,9 @@ void nhrp_interface_init(void) { hook_register_prio(if_add, 0, nhrp_if_new_hook); hook_register_prio(if_del, 0, nhrp_if_delete_hook); + + nhrp_gre_list = hash_create(nhrp_gre_info_key, nhrp_gre_info_cmp, + "NHRP GRE list Hash"); } void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi) @@ -102,14 +143,16 @@ static void nhrp_interface_update_source(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; - if (!nifp->source || !nifp->nbmaifp - || (ifindex_t)nifp->linkidx == nifp->nbmaifp->ifindex) + if (!nifp->source || !nifp->nbmaifp || + ((ifindex_t)nifp->link_idx == nifp->nbmaifp->ifindex && + (nifp->link_vrf_id == nifp->nbmaifp->vrf_id))) return; - nifp->linkidx = nifp->nbmaifp->ifindex; - debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d", ifp->name, - nifp->linkidx); - netlink_gre_set_link(ifp->ifindex, nifp->linkidx); + nifp->link_idx = nifp->nbmaifp->ifindex; + nifp->link_vrf_id = nifp->nbmaifp->vrf_id; + debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d, vr %u", + ifp->name, nifp->link_idx, nifp->link_vrf_id); + nhrp_send_zebra_gre_source_set(ifp, nifp->link_idx, nifp->link_vrf_id); } static void nhrp_interface_interface_notifier(struct notifier_block *n, @@ -136,7 +179,8 @@ static void nhrp_interface_interface_notifier(struct notifier_block *n, } } -static void nhrp_interface_update_nbma(struct interface *ifp) +void nhrp_interface_update_nbma(struct interface *ifp, + struct nhrp_gre_info *gre_info) { struct nhrp_interface *nifp = ifp->info, *nbmanifp = NULL; struct interface *nbmaifp = NULL; @@ -145,21 +189,32 @@ static void nhrp_interface_update_nbma(struct interface *ifp) sockunion_family(&nbma) = AF_UNSPEC; if (nifp->source) - nbmaifp = if_lookup_by_name(nifp->source, VRF_DEFAULT); + nbmaifp = if_lookup_by_name(nifp->source, nifp->link_vrf_id); switch (ifp->ll_type) { case ZEBRA_LLT_IPGRE: { struct in_addr saddr = {0}; - netlink_gre_get_info(ifp->ifindex, &nifp->grekey, - &nifp->linkidx, &saddr); + + if (!gre_info) { + nhrp_send_zebra_gre_request(ifp); + return; + } + nifp->i_grekey = gre_info->ikey; + nifp->o_grekey = gre_info->okey; + nifp->link_idx = gre_info->ifindex_link; + nifp->link_vrf_id = gre_info->vrfid_link; + saddr.s_addr = gre_info->vtep_ip.s_addr; + debugf(NHRP_DEBUG_IF, "%s: GRE: %x %x %x", ifp->name, - nifp->grekey, nifp->linkidx, saddr.s_addr); - if (saddr.s_addr != INADDR_ANY) - sockunion_set(&nbma, AF_INET, (uint8_t *)&saddr.s_addr, + nifp->i_grekey, nifp->link_idx, saddr.s_addr); + if (saddr.s_addr) + sockunion_set(&nbma, AF_INET, + (uint8_t *)&saddr.s_addr, sizeof(saddr.s_addr)); - else if (!nbmaifp && nifp->linkidx != IFINDEX_INTERNAL) + else if (!nbmaifp && nifp->link_idx != IFINDEX_INTERNAL) nbmaifp = - if_lookup_by_index(nifp->linkidx, VRF_DEFAULT); + if_lookup_by_index(nifp->link_idx, + nifp->link_vrf_id); } break; default: break; @@ -322,7 +377,7 @@ int nhrp_ifp_create(struct interface *ifp) ifp->name, ifp->ifindex, ifp->ll_type, if_link_type_str(ifp->ll_type)); - nhrp_interface_update_nbma(ifp); + nhrp_interface_update_nbma(ifp, NULL); return 0; } @@ -402,7 +457,7 @@ static void nhrp_interface_update_cache_config(struct interface *ifp, bool avail int nhrp_ifp_up(struct interface *ifp) { debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name); - nhrp_interface_update_nbma(ifp); + nhrp_interface_update_nbma(ifp, NULL); return 0; } @@ -493,5 +548,5 @@ void nhrp_interface_set_source(struct interface *ifp, const char *ifname) free(nifp->source); nifp->source = ifname ? strdup(ifname) : NULL; - nhrp_interface_update_nbma(ifp); + nhrp_interface_update_nbma(ifp, NULL); } diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index e9bce3e09..c2111a770 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -26,7 +26,6 @@ #include "filter.h" #include "nhrpd.h" -#include "netlink.h" #include "nhrp_errors.h" DEFINE_MGROUP(NHRPD, "NHRP"); @@ -154,7 +153,6 @@ int main(int argc, char **argv) assert(nhrpd_privs.change); nhrpd_privs.change(ZPRIVS_RAISE); - netlink_init(); evmgr_init(); nhrp_vc_init(); nhrp_packet_init(); diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 23fa0771e..ee8db277d 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -380,6 +380,7 @@ void nhrp_zebra_init(void) zclient->neighbor_added = nhrp_neighbor_operation; zclient->neighbor_removed = nhrp_neighbor_operation; zclient->neighbor_get = nhrp_neighbor_operation; + zclient->gre_update = nhrp_gre_update; zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs); } @@ -412,6 +413,33 @@ void nhrp_send_zebra_configure_arp(struct interface *ifp, int family) zclient_send_message(zclient); } +void nhrp_send_zebra_gre_source_set(struct interface *ifp, + unsigned int link_idx, + vrf_id_t link_vrf_id) +{ + struct stream *s; + + if (!zclient || zclient->sock < 0) { + zlog_err("%s : zclient not ready", __func__); + return; + } + if (link_idx == IFINDEX_INTERNAL || link_vrf_id == VRF_UNKNOWN) { + /* silently ignore */ + return; + } + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, + ZEBRA_GRE_SOURCE_SET, + ifp->vrf_id); + stream_putl(s, ifp->ifindex); + stream_putl(s, link_idx); + stream_putl(s, link_vrf_id); + stream_putl(s, 0); /* mtu provisioning */ + stream_putw_at(s, 0, stream_get_endp(s)); + zclient_send_message(zclient); +} + void nhrp_send_zebra_nbr(union sockunion *in, union sockunion *out, struct interface *ifp) @@ -429,6 +457,11 @@ void nhrp_send_zebra_nbr(union sockunion *in, zclient_send_message(zclient); } +int nhrp_send_zebra_gre_request(struct interface *ifp) +{ + return zclient_send_zebra_gre_request(zclient, ifp); +} + void nhrp_zebra_terminate(void) { nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP, false); @@ -441,3 +474,48 @@ void nhrp_zebra_terminate(void) route_table_finish(zebra_rib[AFI_IP]); route_table_finish(zebra_rib[AFI_IP6]); } + +void nhrp_gre_update(ZAPI_CALLBACK_ARGS) +{ + struct stream *s; + struct nhrp_gre_info gre_info, *val; + struct interface *ifp; + + /* result */ + s = zclient->ibuf; + if (vrf_id != VRF_DEFAULT) + return; + + /* read GRE information */ + STREAM_GETL(s, gre_info.ifindex); + STREAM_GETL(s, gre_info.ikey); + STREAM_GETL(s, gre_info.okey); + STREAM_GETL(s, gre_info.ifindex_link); + STREAM_GETL(s, gre_info.vrfid_link); + STREAM_GETL(s, gre_info.vtep_ip.s_addr); + STREAM_GETL(s, gre_info.vtep_ip_remote.s_addr); + if (gre_info.ifindex == IFINDEX_INTERNAL) + val = NULL; + else + val = hash_lookup(nhrp_gre_list, &gre_info); + if (val) { + if (gre_info.vtep_ip.s_addr != val->vtep_ip.s_addr || + gre_info.vrfid_link != val->vrfid_link || + gre_info.ifindex_link != val->ifindex_link || + gre_info.ikey != val->ikey || + gre_info.okey != val->okey) { + /* update */ + memcpy(val, &gre_info, sizeof(struct nhrp_gre_info)); + } + } else { + val = nhrp_gre_info_alloc(&gre_info); + } + ifp = if_lookup_by_index(gre_info.ifindex, vrf_id); + debugf(NHRP_DEBUG_EVENT, "%s: gre interface %d vr %d obtained from system", + ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id); + if (ifp) + nhrp_interface_update_nbma(ifp, val); + return; +stream_failure: + zlog_err("%s(): error reading response ..", __func__); +} diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 730f9b7d1..17abb0476 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -86,14 +86,22 @@ static inline int notifier_active(struct notifier_list *l) return !list_empty(&l->notifier_head); } +extern struct hash *nhrp_gre_list; + void nhrp_zebra_init(void); void nhrp_zebra_terminate(void); void nhrp_send_zebra_configure_arp(struct interface *ifp, int family); void nhrp_send_zebra_nbr(union sockunion *in, union sockunion *out, struct interface *ifp); -void nhrp_send_zebra_configure_arp(struct interface *ifp, - int family); + +void nhrp_send_zebra_gre_source_set(struct interface *ifp, + unsigned int link_idx, + vrf_id_t link_vrf_id); + +extern int nhrp_send_zebra_gre_request(struct interface *ifp); +extern struct nhrp_gre_info *nhrp_gre_info_alloc(struct nhrp_gre_info *p); + struct zbuf; struct nhrp_vc; struct nhrp_cache; @@ -300,8 +308,10 @@ struct nhrp_interface { char *ipsec_profile, *ipsec_fallback_profile, *source; union sockunion nbma; union sockunion nat_nbma; - unsigned int linkidx; - uint32_t grekey; + unsigned int link_idx; + unsigned int link_vrf_id; + uint32_t i_grekey; + uint32_t o_grekey; struct hash *peer_hash; struct hash *cache_config_hash; @@ -325,6 +335,18 @@ struct nhrp_interface { } afi[AFI_MAX]; }; +struct nhrp_gre_info { + ifindex_t ifindex; + struct in_addr vtep_ip; /* IFLA_GRE_LOCAL */ + struct in_addr vtep_ip_remote; /* IFLA_GRE_REMOTE */ + uint32_t ikey; + uint32_t okey; + ifindex_t ifindex_link; /* Interface index of interface + * linked with GRE + */ + vrf_id_t vrfid_link; +}; + extern struct zebra_privs_t nhrpd_privs; int sock_open_unix(const char *path); @@ -332,6 +354,8 @@ int sock_open_unix(const char *path); void nhrp_interface_init(void); void nhrp_interface_update(struct interface *ifp); void nhrp_interface_update_mtu(struct interface *ifp, afi_t afi); +void nhrp_interface_update_nbma(struct interface *ifp, + struct nhrp_gre_info *gre_info); int nhrp_interface_add(ZAPI_CALLBACK_ARGS); int nhrp_interface_delete(ZAPI_CALLBACK_ARGS); @@ -340,6 +364,7 @@ int nhrp_interface_down(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS); void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS); +void nhrp_gre_update(ZAPI_CALLBACK_ARGS); void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index d00aecc1e..9a186d6ed 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -13,7 +13,6 @@ nhrpd_nhrpd_LDADD = lib/libfrr.la lib/libfrrcares.la $(LIBCAP) nhrpd_nhrpd_SOURCES = \ nhrpd/linux.c \ nhrpd/netlink_arp.c \ - nhrpd/netlink_gre.c \ nhrpd/nhrp_cache.c \ nhrpd/nhrp_errors.c \ nhrpd/nhrp_event.c \ diff --git a/zebra/debug.c b/zebra/debug.c index a8ddf6ba6..88a3d9881 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -178,7 +178,7 @@ DEFPY (debug_zebra_mpls, return CMD_SUCCESS; } -DEFUN (debug_zebra_vxlan, +DEFPY (debug_zebra_vxlan, debug_zebra_vxlan_cmd, "debug zebra vxlan", DEBUG_STR diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index e7d8b318e..fbf64439e 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -29,10 +29,13 @@ * Reference - https://sourceware.org/ml/libc-alpha/2013-01/msg00599.html */ #define _LINUX_IN6_H +#define _LINUX_IF_H +#define _LINUX_IP_H #include <netinet/if_ether.h> #include <linux/if_bridge.h> #include <linux/if_link.h> +#include <linux/if_tunnel.h> #include <net/if_arp.h> #include <linux/sockios.h> #include <linux/ethtool.h> @@ -70,6 +73,7 @@ #include "zebra/zebra_errors.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_evpn_mh.h" +#include "zebra/zebra_l2.h" extern struct zebra_privs_t zserv_privs; @@ -289,6 +293,8 @@ static void netlink_determine_zebra_iftype(const char *kind, *zif_type = ZEBRA_IF_BOND; else if (strcmp(kind, "bond_slave") == 0) *zif_type = ZEBRA_IF_BOND_SLAVE; + else if (strcmp(kind, "gre") == 0) + *zif_type = ZEBRA_IF_GRE; } #define parse_rtattr_nested(tb, max, rta) \ @@ -458,6 +464,80 @@ uint32_t kernel_get_speed(struct interface *ifp, int *error) return get_iflink_speed(ifp, error); } +static ssize_t +netlink_gre_set_msg_encoder(struct zebra_dplane_ctx *ctx, void *buf, + size_t buflen) +{ + struct { + struct nlmsghdr n; + struct ifinfomsg ifi; + char buf[]; + } *req = buf; + uint32_t link_idx; + unsigned int mtu; + struct rtattr *rta_info, *rta_data; + const struct zebra_l2info_gre *gre_info; + + if (buflen < sizeof(*req)) + return 0; + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_type = RTM_NEWLINK; + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req->n.nlmsg_flags = NLM_F_REQUEST; + + req->ifi.ifi_index = dplane_ctx_get_ifindex(ctx); + + gre_info = dplane_ctx_gre_get_info(ctx); + if (!gre_info) + return 0; + + req->ifi.ifi_change = 0xFFFFFFFF; + link_idx = dplane_ctx_gre_get_link_ifindex(ctx); + mtu = dplane_ctx_gre_get_mtu(ctx); + + if (mtu && !nl_attr_put32(&req->n, buflen, IFLA_MTU, mtu)) + return 0; + + rta_info = nl_attr_nest(&req->n, buflen, IFLA_LINKINFO); + if (!rta_info) + return 0; + + if (!nl_attr_put(&req->n, buflen, IFLA_INFO_KIND, "gre", 3)) + return 0; + + rta_data = nl_attr_nest(&req->n, buflen, IFLA_INFO_DATA); + if (!rta_data) + return 0; + + if (!nl_attr_put32(&req->n, buflen, IFLA_GRE_LINK, link_idx)) + return 0; + + if (gre_info->vtep_ip.s_addr && + !nl_attr_put32(&req->n, buflen, IFLA_GRE_LOCAL, + gre_info->vtep_ip.s_addr)) + return 0; + + if (gre_info->vtep_ip_remote.s_addr && + !nl_attr_put32(&req->n, buflen, IFLA_GRE_REMOTE, + gre_info->vtep_ip_remote.s_addr)) + return 0; + + if (gre_info->ikey && + !nl_attr_put32(&req->n, buflen, IFLA_GRE_IKEY, + gre_info->ikey)) + return 0; + if (gre_info->okey && + !nl_attr_put32(&req->n, buflen, IFLA_GRE_IKEY, + gre_info->okey)) + return 0; + + nl_attr_nest_end(&req->n, rta_data); + nl_attr_nest_end(&req->n, rta_info); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + static int netlink_extract_bridge_info(struct rtattr *link_data, struct zebra_l2info_bridge *bridge_info) { @@ -492,6 +572,47 @@ static int netlink_extract_vlan_info(struct rtattr *link_data, return 0; } +static int netlink_extract_gre_info(struct rtattr *link_data, + struct zebra_l2info_gre *gre_info) +{ + struct rtattr *attr[IFLA_GRE_MAX + 1]; + + memset(gre_info, 0, sizeof(*gre_info)); + memset(attr, 0, sizeof(attr)); + parse_rtattr_nested(attr, IFLA_GRE_MAX, link_data); + + if (!attr[IFLA_GRE_LOCAL]) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "IFLA_GRE_LOCAL missing from GRE IF message"); + } else + gre_info->vtep_ip = + *(struct in_addr *)RTA_DATA(attr[IFLA_GRE_LOCAL]); + if (!attr[IFLA_GRE_REMOTE]) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "IFLA_GRE_REMOTE missing from GRE IF message"); + } else + gre_info->vtep_ip_remote = + *(struct in_addr *)RTA_DATA(attr[IFLA_GRE_REMOTE]); + + if (!attr[IFLA_GRE_LINK]) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("IFLA_GRE_LINK missing from GRE IF message"); + } else { + gre_info->ifindex_link = + *(ifindex_t *)RTA_DATA(attr[IFLA_GRE_LINK]); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("IFLA_GRE_LINK obtained is %u", + gre_info->ifindex_link); + } + if (attr[IFLA_GRE_IKEY]) + gre_info->ikey = *(uint32_t *)RTA_DATA(attr[IFLA_GRE_IKEY]); + if (attr[IFLA_GRE_OKEY]) + gre_info->okey = *(uint32_t *)RTA_DATA(attr[IFLA_GRE_OKEY]); + return 0; +} + static int netlink_extract_vxlan_info(struct rtattr *link_data, struct zebra_l2info_vxlan *vxl_info) { @@ -572,6 +693,16 @@ static void netlink_interface_update_l2info(struct interface *ifp, vxlan_info.ifindex_link) zebra_if_update_link(ifp, vxlan_info.ifindex_link, link_nsid); + } else if (IS_ZEBRA_IF_GRE(ifp)) { + struct zebra_l2info_gre gre_info; + + netlink_extract_gre_info(link_data, &gre_info); + gre_info.link_nsid = link_nsid; + zebra_l2_greif_add_update(ifp, &gre_info, add); + if (link_nsid != NS_UNKNOWN && + gre_info.ifindex_link) + zebra_if_update_link(ifp, gre_info.ifindex_link, + link_nsid); } } @@ -934,6 +1065,20 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, return netlink_request(netlink_cmd, &req); } +enum netlink_msg_status +netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) +{ + enum dplane_op_e op; + enum netlink_msg_status ret; + + op = dplane_ctx_get_op(ctx); + assert(op == DPLANE_OP_GRE_SET); + + ret = netlink_batch_add_msg(bth, ctx, netlink_gre_set_msg_encoder, false); + + return ret; +} + /* Interface lookup by netlink socket. */ int interface_lookup_netlink(struct zebra_ns *zns) { diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 0bbba81ca..4f09b10b7 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -33,6 +33,9 @@ extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int interface_lookup_netlink(struct zebra_ns *zns); extern enum netlink_msg_status +netlink_put_gre_set_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); + +extern enum netlink_msg_status netlink_put_address_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); diff --git a/zebra/interface.c b/zebra/interface.c index e7357cb30..7fd967dd8 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1066,8 +1066,9 @@ void if_up(struct interface *ifp) zif->link_ifindex); if (link_if) zebra_vxlan_svi_up(ifp, link_if); - } else if (IS_ZEBRA_IF_MACVLAN(ifp)) + } else if (IS_ZEBRA_IF_MACVLAN(ifp)) { zebra_vxlan_macvlan_up(ifp); + } if (zif->es_info.es) zebra_evpn_es_if_oper_state_change(zif, true /*up*/); @@ -1108,8 +1109,9 @@ void if_down(struct interface *ifp) zif->link_ifindex); if (link_if) zebra_vxlan_svi_down(ifp, link_if); - } else if (IS_ZEBRA_IF_MACVLAN(ifp)) + } else if (IS_ZEBRA_IF_MACVLAN(ifp)) { zebra_vxlan_macvlan_down(ifp); + } if (zif->es_info.es) zebra_evpn_es_if_oper_state_change(zif, false /*up*/); @@ -1305,6 +1307,9 @@ static const char *zebra_ziftype_2str(zebra_iftype_t zif_type) case ZEBRA_IF_MACVLAN: return "macvlan"; + case ZEBRA_IF_GRE: + return "GRE"; + default: return "Unknown"; } @@ -1577,6 +1582,28 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) ifp->name); } vty_out(vty, "\n"); + } else if (IS_ZEBRA_IF_GRE(ifp)) { + struct zebra_l2info_gre *gre_info; + + gre_info = &zebra_if->l2info.gre; + if (gre_info->vtep_ip.s_addr != INADDR_ANY) { + vty_out(vty, " VTEP IP: %pI4", &gre_info->vtep_ip); + if (gre_info->vtep_ip_remote.s_addr != INADDR_ANY) + vty_out(vty, " , remote %pI4", + &gre_info->vtep_ip_remote); + vty_out(vty, "\n"); + } + if (gre_info->ifindex_link && + (gre_info->link_nsid != NS_UNKNOWN)) { + struct interface *ifp; + + ifp = if_lookup_by_index_per_ns( + zebra_ns_lookup(gre_info->link_nsid), + gre_info->ifindex_link); + vty_out(vty, " Link Interface %s\n", + ifp == NULL ? "Unknown" : + ifp->name); + } } if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) { diff --git a/zebra/interface.h b/zebra/interface.h index 24bc70cb9..df4872d48 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -263,6 +263,7 @@ typedef enum { ZEBRA_IF_VETH, /* VETH interface*/ ZEBRA_IF_BOND, /* Bond */ ZEBRA_IF_BOND_SLAVE, /* Bond */ + ZEBRA_IF_GRE, /* GRE interface */ } zebra_iftype_t; /* Zebra "slave" interface type */ @@ -442,6 +443,9 @@ DECLARE_HOOK(zebra_if_config_wr, (struct vty * vty, struct interface *ifp), #define IS_ZEBRA_IF_BOND(ifp) \ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_BOND) +#define IS_ZEBRA_IF_GRE(ifp) \ + (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_GRE) + #define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \ (((struct zebra_if *)(ifp->info))->zif_slave_type \ == ZEBRA_IF_SLAVE_BRIDGE) diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index adb61023c..cd22e9573 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -1360,6 +1360,9 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_IPSET_ENTRY_DELETE: return FRR_NETLINK_ERROR; + case DPLANE_OP_GRE_SET: + return netlink_put_gre_set_msg(bth, ctx); + case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } diff --git a/zebra/rt.h b/zebra/rt.h index daaa926a7..f79ddbe95 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -81,9 +81,6 @@ extern int mpls_kernel_init(void); extern uint32_t kernel_get_speed(struct interface *ifp, int *error); extern int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *mroute); -extern int kernel_configure_if_link(struct interface *ifp, - struct interface *link_ifp, ns_id_t ns_id); - /* * Southbound Initialization routines to get initial starting * state. diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index ada828d01..006513ac9 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -394,12 +394,6 @@ enum zebra_dplane_result kernel_mac_update_ctx(struct zebra_dplane_ctx *ctx) return ZEBRA_DPLANE_REQUEST_SUCCESS; } -int kernel_configure_if_link(struct interface *ifp, struct interface *link_ifp, - ns_id_t ns_id) -{ - return 0; -} - extern int kernel_interface_set_master(struct interface *master, struct interface *slave) { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 77a9188fe..55f8edd27 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -3240,6 +3240,61 @@ stream_failure: return; } +static inline void zebra_gre_get(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + ifindex_t idx; + struct interface *ifp; + struct zebra_if *zebra_if = NULL; + struct zebra_l2info_gre *gre_info; + struct interface *ifp_link = NULL; + vrf_id_t vrf_id_link = VRF_UNKNOWN; + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + + s = msg; + STREAM_GETL(s, idx); + ifp = if_lookup_by_index(idx, vrf_id); + + if (ifp) + zebra_if = ifp->info; + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, ZEBRA_GRE_UPDATE, vrf_id); + + if (ifp && IS_ZEBRA_IF_GRE(ifp) && zebra_if) { + gre_info = &zebra_if->l2info.gre; + + stream_putl(s, idx); + stream_putl(s, gre_info->ikey); + stream_putl(s, gre_info->ikey); + stream_putl(s, gre_info->ifindex_link); + + ifp_link = if_lookup_by_index_per_ns( + zebra_ns_lookup(gre_info->link_nsid), + gre_info->ifindex_link); + if (ifp_link) + vrf_id_link = ifp_link->vrf_id; + stream_putl(s, vrf_id_link); + stream_putl(s, gre_info->vtep_ip.s_addr); + stream_putl(s, gre_info->vtep_ip_remote.s_addr); + } else { + stream_putl(s, idx); + stream_putl(s, 0); + stream_putl(s, 0); + stream_putl(s, IFINDEX_INTERNAL); + stream_putl(s, VRF_UNKNOWN); + stream_putl(s, 0); + } + /* Write packet size. */ + stream_putw_at(s, 0, stream_get_endp(s)); + zserv_send_message(client, s); + + return; + stream_failure: + return; +} + static inline void zebra_configure_arp(ZAPI_HANDLER_ARGS) { struct stream *s; @@ -3373,6 +3428,57 @@ stream_failure: return; } +static inline void zebra_gre_source_set(ZAPI_HANDLER_ARGS) +{ + struct stream *s; + ifindex_t idx, link_idx; + vrf_id_t link_vrf_id; + struct interface *ifp; + struct interface *ifp_link; + vrf_id_t vrf_id = zvrf->vrf->vrf_id; + struct zebra_if *zif, *gre_zif; + struct zebra_l2info_gre *gre_info; + unsigned int mtu; + + s = msg; + STREAM_GETL(s, idx); + ifp = if_lookup_by_index(idx, vrf_id); + STREAM_GETL(s, link_idx); + STREAM_GETL(s, link_vrf_id); + STREAM_GETL(s, mtu); + + ifp_link = if_lookup_by_index(link_idx, link_vrf_id); + if (!ifp_link || !ifp) { + zlog_warn("GRE (index %u, VRF %u) or GRE link interface (index %u, VRF %u) not found, when setting GRE params", + idx, vrf_id, link_idx, link_vrf_id); + return; + } + + if (!IS_ZEBRA_IF_GRE(ifp)) + return; + + gre_zif = (struct zebra_if *)ifp->info; + zif = (struct zebra_if *)ifp_link->info; + if (!zif || !gre_zif) + return; + + gre_info = &zif->l2info.gre; + if (!gre_info) + return; + + if (!mtu) + mtu = ifp->mtu; + + /* if gre link already set or mtu did not change, do not set it */ + if (gre_zif->link && gre_zif->link == ifp_link && mtu == ifp->mtu) + return; + + dplane_gre_set(ifp, ifp_link, mtu, gre_info); + + stream_failure: + return; +} + static void zsend_error_msg(struct zserv *client, enum zebra_error_types error, struct zmsghdr *bad_hdr) { @@ -3488,6 +3594,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_NHRP_NEIGH_REGISTER] = zebra_neigh_register, [ZEBRA_NHRP_NEIGH_UNREGISTER] = zebra_neigh_unregister, [ZEBRA_CONFIGURE_ARP] = zebra_configure_arp, + [ZEBRA_GRE_GET] = zebra_gre_get, + [ZEBRA_GRE_SOURCE_SET] = zebra_gre_source_set, }; /* diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index c8ee8f905..a8df0c56c 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -271,6 +271,11 @@ struct dplane_rule_info { struct dplane_ctx_rule old; }; +struct dplane_gre_ctx { + uint32_t link_ifindex; + unsigned int mtu; + struct zebra_l2info_gre info; +}; /* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the @@ -327,6 +332,7 @@ struct zebra_dplane_ctx { struct zebra_pbr_ipset_info info; } ipset_entry; struct dplane_neigh_table neightable; + struct dplane_gre_ctx gre; } u; /* Namespace info, used especially for netlink kernel communication */ @@ -469,6 +475,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_neightable_in; _Atomic uint32_t dg_neightable_errors; + _Atomic uint32_t dg_gre_set_in; + _Atomic uint32_t dg_gre_set_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -713,6 +722,9 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) } list_delete(&ctx->u.iptable.interface_name_list); } + break; + case DPLANE_OP_GRE_SET: + break; } } @@ -979,6 +991,10 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_NEIGH_TABLE_UPDATE: ret = "NEIGH_TABLE_UPDATE"; break; + + case DPLANE_OP_GRE_SET: + ret = "GRE_SET"; + break; } return ret; @@ -1772,6 +1788,31 @@ uint32_t dplane_ctx_neigh_get_update_flags(const struct zebra_dplane_ctx *ctx) return ctx->u.neigh.update_flags; } +/* Accessor for GRE set */ +uint32_t +dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.gre.link_ifindex; +} + +unsigned int +dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.gre.mtu; +} + +const struct zebra_l2info_gre * +dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &ctx->u.gre.info; +} + /* Accessors for PBR rule information */ int dplane_ctx_rule_get_sock(const struct zebra_dplane_ctx *ctx) { @@ -4126,6 +4167,71 @@ dplane_pbr_ipset_entry_delete(struct zebra_pbr_ipset_entry *ipset) } /* + * Common helper api for GRE set + */ +enum zebra_dplane_result +dplane_gre_set(struct interface *ifp, struct interface *ifp_link, + unsigned int mtu, const struct zebra_l2info_gre *gre_info) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + struct zebra_dplane_ctx *ctx; + enum dplane_op_e op = DPLANE_OP_GRE_SET; + int ret; + struct zebra_ns *zns; + + ctx = dplane_ctx_alloc(); + + if (!ifp) + return result; + + if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) { + zlog_debug("init dplane ctx %s: if %s link %s%s", + dplane_op2str(op), ifp->name, + ifp_link ? "set" : "unset", ifp_link ? + ifp_link->name : ""); + } + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + zns = zebra_ns_lookup(ifp->vrf_id); + if (!zns) + return result; + dplane_ctx_ns_init(ctx, zns, false); + + dplane_ctx_set_ifname(ctx, ifp->name); + ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_ifindex = ifp->ifindex; + if (ifp_link) + ctx->u.gre.link_ifindex = ifp_link->ifindex; + else + ctx->u.gre.link_ifindex = 0; + if (gre_info) + memcpy(&ctx->u.gre.info, gre_info, sizeof(ctx->u.gre.info)); + ctx->u.gre.mtu = mtu; + + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* Enqueue context for processing */ + ret = dplane_update_enqueue(ctx); + + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_gre_set_in, 1, + memory_order_relaxed); + + if (ret == AOK) + result = ZEBRA_DPLANE_REQUEST_QUEUED; + else { + atomic_fetch_add_explicit( + &zdplane_info.dg_gre_set_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + result = ZEBRA_DPLANE_REQUEST_FAILURE; + } + return result; +} + +/* * Handler for 'show dplane' */ int dplane_show_helper(struct vty *vty, bool detailed) @@ -4234,6 +4340,13 @@ int dplane_show_helper(struct vty *vty, bool detailed) memory_order_relaxed); vty_out(vty, "Neighbor Table updates: %"PRIu64"\n", incoming); vty_out(vty, "Neighbor Table errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_gre_set_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_gre_set_errors, + memory_order_relaxed); + vty_out(vty, "GRE set updates: %"PRIu64"\n", incoming); + vty_out(vty, "GRE set errors: %"PRIu64"\n", errs); return CMD_SUCCESS; } @@ -4680,6 +4793,12 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifname(ctx), family2str(dplane_ctx_neightable_get_family(ctx))); break; + case DPLANE_OP_GRE_SET: + zlog_debug("Dplane gre set op %s, ifp %s, link %u", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifname(ctx), + ctx->u.gre.link_ifindex); + break; } } @@ -4808,6 +4927,12 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) memory_order_relaxed); break; + case DPLANE_OP_GRE_SET: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit( + &zdplane_info.dg_gre_set_errors, 1, + memory_order_relaxed); + break; /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 8d51d93cd..3a8536dda 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -171,6 +171,7 @@ enum dplane_op_e { DPLANE_OP_NEIGH_IP_DELETE, DPLANE_OP_NEIGH_TABLE_UPDATE, + DPLANE_OP_GRE_SET, }; /* @@ -527,6 +528,14 @@ dplane_ctx_neightable_get_mcast_probes(const struct zebra_dplane_ctx *ctx); uint32_t dplane_ctx_neightable_get_ucast_probes(const struct zebra_dplane_ctx *ctx); +/* Accessor for GRE set */ +uint32_t +dplane_ctx_gre_get_link_ifindex(const struct zebra_dplane_ctx *ctx); +unsigned int +dplane_ctx_gre_get_mtu(const struct zebra_dplane_ctx *ctx); +const struct zebra_l2info_gre * +dplane_ctx_gre_get_info(const struct zebra_dplane_ctx *ctx); + /* Namespace info - esp. for netlink communication */ const struct zebra_dplane_info *dplane_ctx_get_ns( const struct zebra_dplane_ctx *ctx); @@ -695,6 +704,13 @@ enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, const uint32_t ucast_probes, const uint32_t mcast_probes); +/* + * Enqueue a GRE set + */ +enum zebra_dplane_result +dplane_gre_set(struct interface *ifp, struct interface *ifp_link, + unsigned int mtu, const struct zebra_l2info_gre *gre_info); + /* Forward ref of zebra_pbr_rule */ struct zebra_pbr_rule; diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index fc0382a6c..200a977a6 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -134,6 +134,7 @@ enum zebra_log_refs { EC_ZEBRA_DUPLICATE_NHG_MESSAGE, EC_ZEBRA_VRF_MISCONFIGURED, EC_ZEBRA_ES_CREATE, + EC_ZEBRA_GRE_SET_UPDATE, }; void zebra_error_init(void); diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index c3fbff272..71fac556e 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -290,6 +290,32 @@ void zebra_l2_vlanif_update(struct interface *ifp, } /* + * Update L2 info for a GRE interface. This is called upon interface + * addition as well as update. Upon add/update, need to inform + * clients about GRE information. + */ +void zebra_l2_greif_add_update(struct interface *ifp, + struct zebra_l2info_gre *gre_info, int add) +{ + struct zebra_if *zif; + struct in_addr old_vtep_ip; + + zif = ifp->info; + assert(zif); + + if (add) { + memcpy(&zif->l2info.gre, gre_info, sizeof(*gre_info)); + return; + } + + old_vtep_ip = zif->l2info.gre.vtep_ip; + if (IPV4_ADDR_SAME(&old_vtep_ip, &gre_info->vtep_ip)) + return; + + zif->l2info.gre.vtep_ip = gre_info->vtep_ip; +} + +/* * Update L2 info for a VxLAN interface. This is called upon interface * addition as well as update. Upon add, need to invoke the VNI create * function. Upon update, the params of interest are the local tunnel diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 183443028..6572f344c 100644 --- a/zebra/zebra_l2.h +++ b/zebra/zebra_l2.h @@ -54,6 +54,18 @@ struct zebra_l2info_vlan { vlanid_t vid; /* VLAN id */ }; +/* zebra L2 interface information - GRE interface */ +struct zebra_l2info_gre { + struct in_addr vtep_ip; /* IFLA_GRE_LOCAL */ + struct in_addr vtep_ip_remote; /* IFLA_GRE_REMOTE */ + uint32_t ikey; + uint32_t okey; + ifindex_t ifindex_link; /* Interface index of interface + * linked with GRE + */ + ns_id_t link_nsid; +}; + /* zebra L2 interface information - VXLAN interface */ struct zebra_l2info_vxlan { vni_t vni; /* VNI */ @@ -75,6 +87,7 @@ union zebra_l2if_info { struct zebra_l2info_bridge br; struct zebra_l2info_vlan vl; struct zebra_l2info_vxlan vxl; + struct zebra_l2info_gre gre; }; /* NOTE: These macros are to be invoked only in the "correct" context. @@ -96,11 +109,15 @@ extern void zebra_l2_bridge_add_update(struct interface *ifp, extern void zebra_l2_bridge_del(struct interface *ifp); extern void zebra_l2_vlanif_update(struct interface *ifp, struct zebra_l2info_vlan *vlan_info); +extern void zebra_l2_greif_add_update(struct interface *ifp, + struct zebra_l2info_gre *vxlan_info, + int add); extern void zebra_l2_vxlanif_add_update(struct interface *ifp, struct zebra_l2info_vxlan *vxlan_info, int add); extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp, vlanid_t access_vlan); +extern void zebra_l2_greif_del(struct interface *ifp); extern void zebra_l2_vxlanif_del(struct interface *ifp); extern void zebra_l2if_update_bridge_slave(struct interface *ifp, ifindex_t bridge_ifindex, diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 47651318a..6b40eae5b 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2965,6 +2965,7 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: break; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index bdacd411b..dbc5c77fd 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4062,6 +4062,7 @@ static int rib_process_dplane_results(struct thread *thread) case DPLANE_OP_NEIGH_DISCOVER: case DPLANE_OP_BR_PORT_UPDATE: case DPLANE_OP_NEIGH_TABLE_UPDATE: + case DPLANE_OP_GRE_SET: case DPLANE_OP_NONE: /* Don't expect this: just return the struct? */ dplane_ctx_fini(&ctx); |