From 077c07cc58be1fbbe28a2df71cd884af87b121a7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 19 Dec 2019 18:33:56 +0100 Subject: [PATCH] zebra: storage of gre information in zebra layer zebra is able to get information about gre tunnels. zebra_gre file is created to handle hooks, but is not yet used. also, debug zebra gre command is done to add gre traces. A zebra_gre file is used for complementary actions that may be needed. Signed-off-by: Philippe Guibert --- include/linux/if_tunnel.h | 71 +++++++++++++++++++++++++++++++++++++++ zebra/debug.c | 2 +- zebra/if_netlink.c | 52 ++++++++++++++++++++++++++++ zebra/interface.c | 31 +++++++++++++++-- zebra/interface.h | 4 +++ zebra/zebra_l2.c | 26 ++++++++++++++ zebra/zebra_l2.h | 17 ++++++++++ 7 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 include/linux/if_tunnel.h diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h new file mode 100644 index 0000000000..982a1b60d0 --- /dev/null +++ b/include/linux/if_tunnel.h @@ -0,0 +1,71 @@ +#ifndef _IF_TUNNEL_H_ +#define _IF_TUNNEL_H_ + +#include +#include +#include +#include +#include + + +#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/zebra/debug.c b/zebra/debug.c index a8ddf6ba64..88a3d98815 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 6aaf9d94f3..bc74babd19 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 #include #include +#include #include #include #include @@ -289,6 +292,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) \ @@ -492,6 +497,43 @@ 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 (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 +614,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); } } diff --git a/zebra/interface.c b/zebra/interface.c index 4b708496a1..5f3ee9428c 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*/); @@ -1105,8 +1106,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*/); @@ -1304,6 +1306,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"; } @@ -1576,6 +1581,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 67eb1176b9..753eb6b58f 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/zebra_l2.c b/zebra/zebra_l2.c index c3fbff2723..71fac556e1 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -289,6 +289,32 @@ void zebra_l2_vlanif_update(struct interface *ifp, memcpy(&zif->l2info.vl, vlan_info, sizeof(*vlan_info)); } +/* + * 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 diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h index 1834430287..6572f344c4 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, -- 2.39.5