summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_packet.h16
-rw-r--r--include/linux/if_tunnel.h71
-rw-r--r--lib/log.c5
-rw-r--r--lib/zclient.c25
-rw-r--r--lib/zclient.h6
-rw-r--r--nhrpd/linux.c22
-rw-r--r--nhrpd/netlink.h11
-rw-r--r--nhrpd/netlink_arp.c8
-rw-r--r--nhrpd/netlink_gre.c152
-rw-r--r--nhrpd/nhrp_interface.c93
-rw-r--r--nhrpd/nhrp_main.c2
-rw-r--r--nhrpd/nhrp_route.c78
-rw-r--r--nhrpd/nhrpd.h33
-rw-r--r--nhrpd/subdir.am1
-rw-r--r--zebra/debug.c2
-rw-r--r--zebra/if_netlink.c145
-rw-r--r--zebra/if_netlink.h3
-rw-r--r--zebra/interface.c31
-rw-r--r--zebra/interface.h4
-rw-r--r--zebra/kernel_netlink.c3
-rw-r--r--zebra/rt.h3
-rw-r--r--zebra/rt_socket.c6
-rw-r--r--zebra/zapi_msg.c108
-rw-r--r--zebra/zebra_dplane.c125
-rw-r--r--zebra/zebra_dplane.h16
-rw-r--r--zebra/zebra_errors.h1
-rw-r--r--zebra/zebra_l2.c26
-rw-r--r--zebra/zebra_l2.h17
-rw-r--r--zebra/zebra_nhg.c1
-rw-r--r--zebra/zebra_rib.c1
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_ */
diff --git a/lib/log.c b/lib/log.c
index 15fdfd4b0..936422104 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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);