Creates GRE devices using rtnetlink and tunnel metadata. If the kernel does not support tunnel metadata, it will return EEXIST because of the fallback tunnel. However, on kernels between v3.10 and v3.12, it will not. So, we need to verify the created tunnel has the tunnel metadata attribute.
This was tested on kernels 4.2.3, 4.3.6, 4.4.9 and RHEL 3.10 based. All of them worked with the system traffic test "datapath - ping over gre tunnel". Also tested on a 3.10 based kernel without the fix for the existing fallback tunnel. That is, the kernel would not return EEXIST. Yet, the test works fine. Signed-off-by: Thadeu Lima de Souza Cascardo <casca...@redhat.com> --- lib/dpif-netlink.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c index 89fd903..7e30341 100644 --- a/lib/dpif-netlink.c +++ b/lib/dpif-netlink.c @@ -25,6 +25,7 @@ #include <net/if.h> #include <linux/types.h> #include <linux/ip.h> +#include <linux/if_tunnel.h> #include <linux/pkt_sched.h> #include <linux/rtnetlink.h> #include <poll.h> @@ -963,6 +964,12 @@ netdev_vxlan_destroy(const char *name) return netdev_linux_destroy(name); } +static int +netdev_gre_destroy(const char *name) +{ + return netdev_linux_destroy(name); +} + /* * On some older systems, these enums are not defined. */ @@ -977,7 +984,12 @@ netdev_vxlan_destroy(const char *name) #define IFLA_VXLAN_COLLECT_METADATA 25 #endif +#if IFLA_GRE_MAX < 18 +#define IFLA_GRE_COLLECT_METADATA 18 +#endif + #define MTU_MAX_VXLAN 1500 +#define MTU_MAX_GRE (0xfff8 - ETH_HEADER_LEN - 4 - IP_HEADER_LEN) static int netdev_vxlan_create(struct netdev *netdev) @@ -1032,6 +1044,114 @@ netdev_vxlan_create(struct netdev *netdev) return err; } +/* + * On some Linux versions, creating the device with IFLA_GRE_COLLECT_METADATA + * will succeed, even though that attribute is not supported. We need to verify + * the device has been created with that attribute. In case it has not, we + * destroy it and use the compat code. + */ +static int +netdev_gre_verify(const char *name) +{ + int err; + struct ofpbuf request, *reply; + struct ifinfomsg *ifmsg; + + static const struct nl_policy rtlink_policy[] = { + [IFLA_LINKINFO] = { .type = NL_A_NESTED }, + }; + static const struct nl_policy linkinfo_policy[] = { + [IFLA_INFO_KIND] = { .type = NL_A_STRING }, + [IFLA_INFO_DATA] = { .type = NL_A_NESTED }, + }; + static const struct nl_policy gre_policy[] = { + [IFLA_GRE_COLLECT_METADATA] = { .type = NL_A_FLAG }, + }; + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, 0, RTM_GETLINK, + NLM_F_REQUEST); + ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg)); + nl_msg_put_string(&request, IFLA_IFNAME, name); + + err = nl_transact(NETLINK_ROUTE, &request, &reply); + if (!err) { + struct nlattr *rtlink[ARRAY_SIZE(rtlink_policy)]; + struct nlattr *linkinfo[ARRAY_SIZE(linkinfo_policy)]; + struct nlattr *gre[ARRAY_SIZE(gre_policy)]; + + err = EINVAL; + ifmsg = ofpbuf_at(reply, NLMSG_HDRLEN, sizeof *ifmsg); + if (nl_policy_parse(reply, NLMSG_HDRLEN + sizeof *ifmsg, + rtlink_policy, rtlink, ARRAY_SIZE(rtlink_policy))) { + if (nl_parse_nested(rtlink[IFLA_LINKINFO], linkinfo_policy, + linkinfo, ARRAY_SIZE(linkinfo_policy)) && + !strcmp(nl_attr_get_string(linkinfo[IFLA_INFO_KIND]), "gre")) { + if (nl_parse_nested(linkinfo[IFLA_INFO_DATA], gre_policy, gre, + ARRAY_SIZE(gre_policy)) && + nl_attr_get_flag(gre[IFLA_GRE_COLLECT_METADATA])) { + err = 0; + } + } + } + ofpbuf_uninit(reply); + } + ofpbuf_uninit(&request); + return err; +} + +static int +netdev_gre_create(struct netdev *netdev) +{ + int err; + struct ofpbuf request, *reply; + size_t linkinfo_off, infodata_off; + char namebuf[NETDEV_VPORT_NAME_BUFSIZE]; + const char *name = netdev_vport_get_dpif_port(netdev, + namebuf, sizeof namebuf); + struct ifinfomsg *ifinfo; + const struct netdev_tunnel_config *tnl_cfg; + tnl_cfg = netdev_get_tunnel_config(netdev); + if (!tnl_cfg) { /* or assert? */ + return EINVAL; + } + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, 0, RTM_NEWLINK, + NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE); + ifinfo = ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg)); + ifinfo->ifi_change = ifinfo->ifi_flags = IFF_UP; + nl_msg_put_string(&request, IFLA_IFNAME, name); + nl_msg_put_u32(&request, IFLA_MTU, MTU_MAX_GRE); + linkinfo_off = nl_msg_start_nested(&request, IFLA_LINKINFO); + nl_msg_put_string(&request, IFLA_INFO_KIND, "gretap"); + infodata_off = nl_msg_start_nested(&request, IFLA_INFO_DATA); + nl_msg_put_flag(&request, IFLA_GRE_COLLECT_METADATA); + nl_msg_end_nested(&request, infodata_off); + nl_msg_end_nested(&request, linkinfo_off); + + err = nl_transact(NETLINK_ROUTE, &request, &reply); + + if (!err) { + ofpbuf_uninit(reply); + } + + if (!err && (err = netdev_gre_verify(name))) { + netdev_gre_destroy(name); + } + + /* + * If tunnel metadata is not supported, EEXIST will be returned for zero + * addresses tunnel. We still need to verify metadata has been set as above. + */ + if (err == EINVAL || err == EEXIST) { + err = EOPNOTSUPP; + } + + ofpbuf_uninit(&request); + return err; +} + #else static int @@ -1041,11 +1161,23 @@ netdev_vxlan_create(struct netdev *netdev OVS_UNUSED) } static int +netdev_gre_create(struct netdev *netdev OVS_UNUSED) +{ + return EOPNOTSUPP; +} + +static int netdev_vxlan_destroy(const char *name OVS_UNUSED) { return EOPNOTSUPP; } +static int +netdev_gre_destroy(const char *name OVS_UNUSED) +{ + return EOPNOTSUPP; +} + #endif static int @@ -1059,6 +1191,7 @@ dpif_netlink_port_create(struct netdev *netdev) case OVS_VPORT_TYPE_VXLAN: return netdev_vxlan_create(netdev); case OVS_VPORT_TYPE_GRE: + return netdev_gre_create(netdev); case OVS_VPORT_TYPE_GENEVE: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: @@ -1079,6 +1212,7 @@ dpif_netlink_port_destroy(const char *name, const char *type) case OVS_VPORT_TYPE_VXLAN: return netdev_vxlan_destroy(name); case OVS_VPORT_TYPE_GRE: + return netdev_gre_destroy(name); case OVS_VPORT_TYPE_GENEVE: case OVS_VPORT_TYPE_NETDEV: case OVS_VPORT_TYPE_INTERNAL: -- 2.5.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev