summaryrefslogtreecommitdiffstats
path: root/zebra/if_netlink.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/if_netlink.c')
-rw-r--r--zebra/if_netlink.c145
1 files changed, 145 insertions, 0 deletions
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)
{