mirror of
https://github.com/openvswitch/ovs
synced 2025-09-04 08:15:25 +00:00
datapath: 64-bit GRE support
Extend GRE to have a 64-bit key. Use GRE sequence number to store upper 32-bits of the key, but this is not standard way of using GRE sequence number. Bug #13186 Signed-off-by: Pravin B Shelar <pshelar@nicira.com> Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
1
NEWS
1
NEWS
@@ -28,6 +28,7 @@ post-v1.8.0
|
||||
program was not included in distribution packaging.)
|
||||
- ovsdb-server now enforces the immutability of immutable columns. This
|
||||
was not enforced in earlier versions due to an oversight.
|
||||
- New support for a nonstandard form of GRE that supports a 64-bit key.
|
||||
- The following features are now deprecated. They will be removed no
|
||||
earlier than February 2013. Please email dev@openvswitch.org with
|
||||
concerns.
|
||||
|
@@ -40,7 +40,8 @@
|
||||
* identifiers.
|
||||
*/
|
||||
#define TNL_T_PROTO_GRE 0
|
||||
#define TNL_T_PROTO_CAPWAP 1
|
||||
#define TNL_T_PROTO_GRE64 1
|
||||
#define TNL_T_PROTO_CAPWAP 2
|
||||
|
||||
/* These flags are only needed when calling tnl_find_port(). */
|
||||
#define TNL_T_KEY_EXACT (1 << 10)
|
||||
|
@@ -54,12 +54,15 @@ static int gre_hdr_len(const struct tnl_mutable_config *mutable)
|
||||
if (mutable->flags & TNL_F_CSUM)
|
||||
len += GRE_HEADER_SECTION;
|
||||
|
||||
if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
|
||||
if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION) {
|
||||
len += GRE_HEADER_SECTION;
|
||||
|
||||
if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64)
|
||||
len += GRE_HEADER_SECTION;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* Returns the least-significant 32 bits of a __be64. */
|
||||
static __be32 be64_get_low32(__be64 x)
|
||||
{
|
||||
@@ -70,6 +73,15 @@ static __be32 be64_get_low32(__be64 x)
|
||||
#endif
|
||||
}
|
||||
|
||||
static __be32 be64_get_high32(__be64 x)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
return (__force __be32)((__force u64)x >> 32);
|
||||
#else
|
||||
return (__force __be32)x;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gre_build_header(const struct vport *vport,
|
||||
const struct tnl_mutable_config *mutable,
|
||||
void *header)
|
||||
@@ -86,11 +98,20 @@ static void gre_build_header(const struct vport *vport,
|
||||
options++;
|
||||
}
|
||||
|
||||
if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
|
||||
if (mutable->flags & TNL_F_OUT_KEY_ACTION) {
|
||||
greh->flags |= GRE_KEY;
|
||||
if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64)
|
||||
greh->flags |= GRE_SEQ;
|
||||
|
||||
if (mutable->out_key)
|
||||
} else if (mutable->out_key) {
|
||||
greh->flags |= GRE_KEY;
|
||||
*options = be64_get_low32(mutable->out_key);
|
||||
if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64) {
|
||||
options++;
|
||||
*options = be64_get_high32(mutable->out_key);
|
||||
greh->flags |= GRE_SEQ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct sk_buff *gre_update_header(const struct vport *vport,
|
||||
@@ -102,11 +123,19 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
|
||||
- GRE_HEADER_SECTION);
|
||||
|
||||
/* Work backwards over the options so the checksum is last. */
|
||||
if (mutable->flags & TNL_F_OUT_KEY_ACTION)
|
||||
*options = be64_get_low32(OVS_CB(skb)->tun_id);
|
||||
|
||||
if (mutable->out_key || mutable->flags & TNL_F_OUT_KEY_ACTION)
|
||||
if (mutable->flags & TNL_F_OUT_KEY_ACTION) {
|
||||
if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64) {
|
||||
/* Set higher 32 bits to seq. */
|
||||
*options = be64_get_high32(OVS_CB(skb)->tun_id);
|
||||
options--;
|
||||
}
|
||||
*options = be64_get_low32(OVS_CB(skb)->tun_id);
|
||||
options--;
|
||||
} else if (mutable->out_key) {
|
||||
options--;
|
||||
if (mutable->key.tunnel_type & TNL_T_PROTO_GRE64)
|
||||
options--;
|
||||
}
|
||||
|
||||
if (mutable->flags & TNL_F_CSUM)
|
||||
*(__sum16 *)options = csum_fold(skb_checksum(skb,
|
||||
@@ -125,17 +154,17 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
|
||||
return skb;
|
||||
}
|
||||
|
||||
/* Zero-extends a __be32 into the least-significant 32 bits of a __be64. */
|
||||
static __be64 be32_extend_to_be64(__be32 x)
|
||||
static __be64 key_to_tunnel_id(__be32 key, __be32 seq)
|
||||
{
|
||||
#ifdef __BIG_ENDIAN
|
||||
return (__force __be64)x;
|
||||
return (__force __be64)((__force u64)seq << 32 | (__force u32)key);
|
||||
#else
|
||||
return (__force __be64)((__force u64)x << 32);
|
||||
return (__force __be64)((__force u64)key << 32 | (__force u32)seq);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
|
||||
static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *tun_id,
|
||||
u32 *tunnel_type)
|
||||
{
|
||||
/* IP and ICMP protocol handlers check that the IHL is valid. */
|
||||
struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
|
||||
@@ -158,14 +187,25 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
|
||||
}
|
||||
|
||||
if (greh->flags & GRE_KEY) {
|
||||
__be32 seq;
|
||||
__be32 gre_key;
|
||||
|
||||
gre_key = *options;
|
||||
hdr_len += GRE_HEADER_SECTION;
|
||||
|
||||
*key = be32_extend_to_be64(*options);
|
||||
options++;
|
||||
} else
|
||||
*key = 0;
|
||||
|
||||
if (unlikely(greh->flags & GRE_SEQ))
|
||||
if (greh->flags & GRE_SEQ) {
|
||||
seq = *options;
|
||||
*tunnel_type = TNL_T_PROTO_GRE64;
|
||||
} else {
|
||||
seq = 0;
|
||||
*tunnel_type = TNL_T_PROTO_GRE;
|
||||
}
|
||||
*tun_id = key_to_tunnel_id(gre_key, seq);
|
||||
} else
|
||||
*tun_id = 0;
|
||||
|
||||
if (greh->flags & GRE_SEQ)
|
||||
hdr_len += GRE_HEADER_SECTION;
|
||||
|
||||
return hdr_len;
|
||||
@@ -179,6 +219,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
|
||||
const int type = icmp_hdr(skb)->type;
|
||||
const int code = icmp_hdr(skb)->code;
|
||||
int mtu = ntohs(icmp_hdr(skb)->un.frag.mtu);
|
||||
u32 tunnel_type;
|
||||
|
||||
struct iphdr *iph;
|
||||
__be16 flags;
|
||||
@@ -203,12 +244,12 @@ static void gre_err(struct sk_buff *skb, u32 info)
|
||||
if (ipv4_is_multicast(iph->daddr))
|
||||
return;
|
||||
|
||||
tunnel_hdr_len = parse_header(iph, &flags, &key);
|
||||
tunnel_hdr_len = parse_header(iph, &flags, &key, &tunnel_type);
|
||||
if (tunnel_hdr_len < 0)
|
||||
return;
|
||||
|
||||
vport = ovs_tnl_find_port(dev_net(skb->dev), iph->saddr, iph->daddr, key,
|
||||
TNL_T_PROTO_GRE, &mutable);
|
||||
tunnel_type, &mutable);
|
||||
if (!vport)
|
||||
return;
|
||||
|
||||
@@ -329,14 +370,14 @@ static int gre_rcv(struct sk_buff *skb)
|
||||
struct iphdr *iph;
|
||||
__be16 flags;
|
||||
__be64 key;
|
||||
u32 tunnel_type;
|
||||
|
||||
if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
|
||||
goto error;
|
||||
|
||||
if (unlikely(!check_checksum(skb)))
|
||||
goto error;
|
||||
|
||||
hdr_len = parse_header(ip_hdr(skb), &flags, &key);
|
||||
hdr_len = parse_header(ip_hdr(skb), &flags, &key, &tunnel_type);
|
||||
if (unlikely(hdr_len < 0))
|
||||
goto error;
|
||||
|
||||
@@ -345,7 +386,7 @@ static int gre_rcv(struct sk_buff *skb)
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
vport = ovs_tnl_find_port(dev_net(skb->dev), iph->daddr, iph->saddr, key,
|
||||
TNL_T_PROTO_GRE, &mutable);
|
||||
tunnel_type, &mutable);
|
||||
if (unlikely(!vport)) {
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
|
||||
goto error;
|
||||
@@ -380,6 +421,19 @@ static struct vport *gre_create(const struct vport_parms *parms)
|
||||
return ovs_tnl_create(parms, &ovs_gre_vport_ops, &gre_tnl_ops);
|
||||
}
|
||||
|
||||
static const struct tnl_ops gre64_tnl_ops = {
|
||||
.tunnel_type = TNL_T_PROTO_GRE64,
|
||||
.ipproto = IPPROTO_GRE,
|
||||
.hdr_len = gre_hdr_len,
|
||||
.build_header = gre_build_header,
|
||||
.update_header = gre_update_header,
|
||||
};
|
||||
|
||||
static struct vport *gre_create64(const struct vport_parms *parms)
|
||||
{
|
||||
return ovs_tnl_create(parms, &ovs_gre64_vport_ops, &gre64_tnl_ops);
|
||||
}
|
||||
|
||||
static const struct net_protocol gre_protocol_handlers = {
|
||||
.handler = gre_rcv,
|
||||
.err_handler = gre_err,
|
||||
@@ -388,10 +442,16 @@ static const struct net_protocol gre_protocol_handlers = {
|
||||
#endif
|
||||
};
|
||||
|
||||
static bool inited;
|
||||
|
||||
static int gre_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (inited)
|
||||
return 0;
|
||||
|
||||
inited = true;
|
||||
err = inet_add_protocol(&gre_protocol_handlers, IPPROTO_GRE);
|
||||
if (err)
|
||||
pr_warn("cannot register gre protocol handler\n");
|
||||
@@ -401,6 +461,11 @@ static int gre_init(void)
|
||||
|
||||
static void gre_exit(void)
|
||||
{
|
||||
if (!inited)
|
||||
return;
|
||||
|
||||
inited = false;
|
||||
|
||||
inet_del_protocol(&gre_protocol_handlers, IPPROTO_GRE);
|
||||
}
|
||||
|
||||
@@ -421,3 +486,21 @@ const struct vport_ops ovs_gre_vport_ops = {
|
||||
.get_operstate = ovs_vport_gen_get_operstate,
|
||||
.send = ovs_tnl_send,
|
||||
};
|
||||
|
||||
const struct vport_ops ovs_gre64_vport_ops = {
|
||||
.type = OVS_VPORT_TYPE_GRE64,
|
||||
.flags = VPORT_F_TUN_ID,
|
||||
.init = gre_init,
|
||||
.exit = gre_exit,
|
||||
.create = gre_create64,
|
||||
.destroy = ovs_tnl_destroy,
|
||||
.set_addr = ovs_tnl_set_addr,
|
||||
.get_name = ovs_tnl_get_name,
|
||||
.get_addr = ovs_tnl_get_addr,
|
||||
.get_options = ovs_tnl_get_options,
|
||||
.set_options = ovs_tnl_set_options,
|
||||
.get_dev_flags = ovs_vport_gen_get_dev_flags,
|
||||
.is_running = ovs_vport_gen_is_running,
|
||||
.get_operstate = ovs_vport_gen_get_operstate,
|
||||
.send = ovs_tnl_send,
|
||||
};
|
||||
|
@@ -41,6 +41,7 @@ static const struct vport_ops *base_vport_ops_list[] = {
|
||||
&ovs_internal_vport_ops,
|
||||
&ovs_patch_vport_ops,
|
||||
&ovs_gre_vport_ops,
|
||||
&ovs_gre64_vport_ops,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
|
||||
&ovs_capwap_vport_ops,
|
||||
#endif
|
||||
|
@@ -254,6 +254,7 @@ extern const struct vport_ops ovs_netdev_vport_ops;
|
||||
extern const struct vport_ops ovs_internal_vport_ops;
|
||||
extern const struct vport_ops ovs_patch_vport_ops;
|
||||
extern const struct vport_ops ovs_gre_vport_ops;
|
||||
extern const struct vport_ops ovs_gre64_vport_ops;
|
||||
extern const struct vport_ops ovs_capwap_vport_ops;
|
||||
|
||||
#endif /* vport.h */
|
||||
|
2
debian/ovs-monitor-ipsec
vendored
2
debian/ovs-monitor-ipsec
vendored
@@ -441,7 +441,7 @@ def main():
|
||||
|
||||
new_interfaces = {}
|
||||
for rec in idl.tables["Interface"].rows.itervalues():
|
||||
if rec.type == "ipsec_gre":
|
||||
if rec.type == "ipsec_gre" or rec.type == "ipsec_gre64":
|
||||
name = rec.name
|
||||
options = rec.options
|
||||
peer_cert_name = "ovs-%s.pem" % (options.get("remote_ip"))
|
||||
|
@@ -185,6 +185,7 @@ enum ovs_vport_type {
|
||||
OVS_VPORT_TYPE_PATCH = 100, /* virtual tunnel connecting two vports */
|
||||
OVS_VPORT_TYPE_GRE, /* GRE tunnel */
|
||||
OVS_VPORT_TYPE_CAPWAP, /* CAPWAP tunnel */
|
||||
OVS_VPORT_TYPE_GRE64 = 104, /* GRE tunnel with 64-bit keys */
|
||||
__OVS_VPORT_TYPE_MAX
|
||||
};
|
||||
|
||||
|
@@ -162,6 +162,14 @@ netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport)
|
||||
return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
|
||||
? "ipsec_gre" : "gre");
|
||||
|
||||
case OVS_VPORT_TYPE_GRE64:
|
||||
if (tnl_port_config_from_nlattr(vport->options, vport->options_len,
|
||||
a)) {
|
||||
break;
|
||||
}
|
||||
return (nl_attr_get_u32(a[OVS_TUNNEL_ATTR_FLAGS]) & TNL_F_IPSEC
|
||||
? "ipsec_gre64" : "gre64");
|
||||
|
||||
case OVS_VPORT_TYPE_CAPWAP:
|
||||
return "capwap";
|
||||
|
||||
@@ -583,9 +591,9 @@ parse_tunnel_config(const char *name, const char *type,
|
||||
uint32_t flags;
|
||||
|
||||
flags = TNL_F_DF_DEFAULT | TNL_F_PMTUD | TNL_F_HDR_CACHE;
|
||||
if (!strcmp(type, "gre")) {
|
||||
if (!strcmp(type, "gre") || !strcmp(type, "gre64")) {
|
||||
is_gre = true;
|
||||
} else if (!strcmp(type, "ipsec_gre")) {
|
||||
} else if (!strcmp(type, "ipsec_gre") || !strcmp(type, "ipsec_gre64")) {
|
||||
is_gre = true;
|
||||
is_ipsec = true;
|
||||
flags |= TNL_F_IPSEC;
|
||||
@@ -970,6 +978,14 @@ netdev_vport_register(void)
|
||||
{ "ipsec_gre", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
|
||||
parse_tunnel_config, unparse_tunnel_config },
|
||||
|
||||
{ OVS_VPORT_TYPE_GRE64,
|
||||
{ "gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
|
||||
parse_tunnel_config, unparse_tunnel_config },
|
||||
|
||||
{ OVS_VPORT_TYPE_GRE64,
|
||||
{ "ipsec_gre64", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
|
||||
parse_tunnel_config, unparse_tunnel_config },
|
||||
|
||||
{ OVS_VPORT_TYPE_CAPWAP,
|
||||
{ "capwap", VPORT_FUNCTIONS(netdev_vport_get_drv_info) },
|
||||
parse_tunnel_config, unparse_tunnel_config },
|
||||
|
@@ -1199,6 +1199,21 @@
|
||||
IPsec tunnel.
|
||||
</dd>
|
||||
|
||||
<dt><code>gre64</code></dt>
|
||||
<dd>
|
||||
It is same as GRE, but it allows 64 bit key. To store higher 32-bits
|
||||
of key, it uses GRE protocol sequence number field. This is non
|
||||
standard use of GRE protocol since OVS does not increment
|
||||
sequence number for every packet at time of encap as expected by
|
||||
standard GRE implementation. See <ref group="Tunnel Options"/>
|
||||
for information on configuring GRE tunnels.
|
||||
</dd>
|
||||
|
||||
<dt><code>ipsec_gre64</code></dt>
|
||||
<dd>
|
||||
Same as IPSEC_GRE except 64 bit key.
|
||||
</dd>
|
||||
|
||||
<dt><code>capwap</code></dt>
|
||||
<dd>
|
||||
An Ethernet tunnel over the UDP transport portion of CAPWAP (RFC
|
||||
@@ -1224,7 +1239,8 @@
|
||||
<group title="Tunnel Options">
|
||||
<p>
|
||||
These options apply to interfaces with <ref column="type"/> of
|
||||
<code>gre</code>, <code>ipsec_gre</code>, and <code>capwap</code>.
|
||||
<code>gre</code>, <code>ipsec_gre</code>, <code>gre64</code>,
|
||||
<code>ipsec_gre64</code>, and <code>capwap</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
Reference in New Issue
Block a user