Skip to content

Commit

Permalink
erspan: add kernel datapath support
Browse files Browse the repository at this point in the history
pass check, check-kernel (4.16-rc4), check-system-userspace

Signed-off-by: William Tu <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
williamtu authored and blp committed May 22, 2018
1 parent 7dc18ae commit 98514ee
Show file tree
Hide file tree
Showing 7 changed files with 435 additions and 10 deletions.
20 changes: 11 additions & 9 deletions lib/dpif-netlink-rtnl.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,6 @@ vport_type_to_kind(enum ovs_vport_type type,
case OVS_VPORT_TYPE_VXLAN:
return "vxlan";
case OVS_VPORT_TYPE_GRE:
case OVS_VPORT_TYPE_ERSPAN:
case OVS_VPORT_TYPE_IP6ERSPAN:
case OVS_VPORT_TYPE_IP6GRE:
if (tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L3) {
return "gre";
} else if (tnl_cfg->pt_mode == NETDEV_PT_LEGACY_L2) {
Expand All @@ -102,6 +99,11 @@ vport_type_to_kind(enum ovs_vport_type type,
}
case OVS_VPORT_TYPE_GENEVE:
return "geneve";
case OVS_VPORT_TYPE_ERSPAN:
return "erspan";
case OVS_VPORT_TYPE_IP6ERSPAN:
return "ip6erspan";
case OVS_VPORT_TYPE_IP6GRE:
case OVS_VPORT_TYPE_NETDEV:
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
Expand Down Expand Up @@ -256,6 +258,9 @@ dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg,
err = dpif_netlink_rtnl_vxlan_verify(tnl_cfg, kind, reply);
break;
case OVS_VPORT_TYPE_GRE:
case OVS_VPORT_TYPE_ERSPAN:
case OVS_VPORT_TYPE_IP6ERSPAN:
case OVS_VPORT_TYPE_IP6GRE:
err = dpif_netlink_rtnl_gre_verify(tnl_cfg, kind, reply);
break;
case OVS_VPORT_TYPE_GENEVE:
Expand All @@ -265,9 +270,6 @@ dpif_netlink_rtnl_verify(const struct netdev_tunnel_config *tnl_cfg,
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
case OVS_VPORT_TYPE_STT:
case OVS_VPORT_TYPE_ERSPAN:
case OVS_VPORT_TYPE_IP6ERSPAN:
case OVS_VPORT_TYPE_IP6GRE:
case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
default:
Expand Down Expand Up @@ -442,14 +444,14 @@ dpif_netlink_rtnl_port_destroy(const char *name, const char *type)
case OVS_VPORT_TYPE_VXLAN:
case OVS_VPORT_TYPE_GRE:
case OVS_VPORT_TYPE_GENEVE:
case OVS_VPORT_TYPE_ERSPAN:
case OVS_VPORT_TYPE_IP6ERSPAN:
case OVS_VPORT_TYPE_IP6GRE:
return dpif_netlink_rtnl_destroy(name);
case OVS_VPORT_TYPE_NETDEV:
case OVS_VPORT_TYPE_INTERNAL:
case OVS_VPORT_TYPE_LISP:
case OVS_VPORT_TYPE_STT:
case OVS_VPORT_TYPE_ERSPAN:
case OVS_VPORT_TYPE_IP6ERSPAN:
case OVS_VPORT_TYPE_IP6GRE:
case OVS_VPORT_TYPE_UNSPEC:
case __OVS_VPORT_TYPE_MAX:
default:
Expand Down
3 changes: 3 additions & 0 deletions lib/dpif-netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,7 +788,10 @@ get_vport_type(const struct dpif_netlink_vport *vport)
return "stt";

case OVS_VPORT_TYPE_ERSPAN:
return "erspan";

case OVS_VPORT_TYPE_IP6ERSPAN:
return "ip6erspan";
case OVS_VPORT_TYPE_IP6GRE:
return "";

Expand Down
152 changes: 152 additions & 0 deletions lib/odp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -2451,6 +2451,7 @@ static const struct attr_len_tbl ovs_tun_key_attr_lens[OVS_TUNNEL_KEY_ATTR_MAX +
.next_max = OVS_VXLAN_EXT_MAX},
[OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = 16 },
[OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 },
[OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = ATTR_LEN_VARIABLE },
};

const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
Expand Down Expand Up @@ -2774,6 +2775,23 @@ odp_tun_key_from_attr__(const struct nlattr *attr, bool is_mask,
case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
tun_metadata_from_geneve_nlattr(a, is_mask, tun);
break;
case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: {
int attr_len = nl_attr_get_size(a);
struct erspan_metadata opts;

memcpy(&opts, nl_attr_get(a), attr_len);

tun->erspan_ver = opts.version;
if (tun->erspan_ver == 1) {
tun->erspan_idx = ntohl(opts.u.index);
} else if (tun->erspan_ver == 2) {
tun->erspan_dir = opts.u.md2.dir;
tun->erspan_hwid = get_hwid(&opts.u.md2);
} else {
VLOG_WARN("%s invalid erspan version\n", __func__);
}
break;
}

default:
/* Allow this to show up as unexpected, if there are unknown
Expand Down Expand Up @@ -2863,6 +2881,22 @@ tun_key_to_attr(struct ofpbuf *a, const struct flow_tnl *tun_key,
tun_metadata_to_geneve_nlattr(tun_key, tun_flow_key, key_buf, a);
}

if ((!tnl_type || !strcmp(tnl_type, "erspan") ||
!strcmp(tnl_type, "ip6erspan")) &&
(tun_key->erspan_ver == 1 || tun_key->erspan_ver == 2)) {
struct erspan_metadata opts;

opts.version = tun_key->erspan_ver;
if (opts.version == 1) {
opts.u.index = htonl(tun_key->erspan_idx);
} else {
opts.u.md2.dir = tun_key->erspan_dir;
set_hwid(&opts.u.md2, tun_key->erspan_hwid);
}
nl_msg_put_unspec(a, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS,
&opts, sizeof(opts));
}

nl_msg_end_nested(a, tun_key_ofs);
}

Expand Down Expand Up @@ -3318,6 +3352,46 @@ format_odp_tun_vxlan_opt(const struct nlattr *attr,
ofpbuf_uninit(&ofp);
}

static void
format_odp_tun_erspan_opt(const struct nlattr *attr,
const struct nlattr *mask_attr, struct ds *ds,
bool verbose)
{
const struct erspan_metadata *opts, *mask;
uint8_t ver, ver_ma, dir, dir_ma, hwid, hwid_ma;

opts = nl_attr_get(attr);
mask = mask_attr ? nl_attr_get(mask_attr) : NULL;

ver = (uint8_t)opts->version;
if (mask) {
ver_ma = (uint8_t)mask->version;
}

format_u8u(ds, "ver", ver, mask ? &ver_ma : NULL, verbose);

if (opts->version == 1) {
if (mask) {
ds_put_format(ds, "idx=%#"PRIx32"/%#"PRIx32",",
ntohl(opts->u.index),
ntohl(mask->u.index));
} else {
ds_put_format(ds, "idx=%#"PRIx32",", ntohl(opts->u.index));
}
} else if (opts->version == 2) {
dir = opts->u.md2.dir;
hwid = opts->u.md2.hwid;
if (mask) {
dir_ma = mask->u.md2.dir;
hwid_ma = mask->u.md2.hwid;
}

format_u8u(ds, "dir", dir, mask ? &dir_ma : NULL, verbose);
format_u8x(ds, "hwid", hwid, mask ? &hwid_ma : NULL, verbose);
}
ds_chomp(ds, ',');
}

#define MASK(PTR, FIELD) PTR ? &PTR->FIELD : NULL

static void
Expand Down Expand Up @@ -3566,6 +3640,9 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
case OVS_TUNNEL_KEY_ATTR_PAD:
break;
case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS:
ds_put_cstr(ds, "erspan(");
format_odp_tun_erspan_opt(a, ma, ds, verbose);
ds_put_cstr(ds, "),");
break;
case __OVS_TUNNEL_KEY_ATTR_MAX:
default:
Expand Down Expand Up @@ -4750,6 +4827,70 @@ scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
return 0;
}

static int
scan_erspan_metadata(const char *s,
struct erspan_metadata *key,
struct erspan_metadata *mask)
{
const char *s_base = s;
uint32_t idx = 0, idx_mask = 0;
uint8_t ver = 0, dir = 0, hwid = 0;
uint8_t ver_mask = 0, dir_mask = 0, hwid_mask = 0;

if (!strncmp(s, "ver=", 4)) {
s += 4;
s += scan_u8(s, &ver, mask ? &ver_mask : NULL);
}

if (s[0] == ',') {
s++;
}

if (ver == 1) {
if (!strncmp(s, "idx=", 4)) {
s += 4;
s += scan_u32(s, &idx, mask ? &idx_mask : NULL);
}

if (!strncmp(s, ")", 1)) {
s += 1;
key->version = ver;
key->u.index = htonl(idx);
if (mask) {
mask->u.index = htonl(idx_mask);
}
}
return s - s_base;

} else if (ver == 2) {
if (!strncmp(s, "dir=", 4)) {
s += 4;
s += scan_u8(s, &dir, mask ? &dir_mask : NULL);
}
if (s[0] == ',') {
s++;
}
if (!strncmp(s, "hwid=", 5)) {
s += 5;
s += scan_u8(s, &hwid, mask ? &hwid_mask : NULL);
}

if (!strncmp(s, ")", 1)) {
s += 1;
key->version = ver;
key->u.md2.hwid = hwid;
key->u.md2.dir = dir;
if (mask) {
mask->u.md2.hwid = hwid_mask;
mask->u.md2.dir = dir_mask;
}
}
return s - s_base;
}

return 0;
}

static int
scan_geneve(const char *s, struct geneve_scan *key, struct geneve_scan *mask)
{
Expand Down Expand Up @@ -4885,6 +5026,15 @@ geneve_to_attr(struct ofpbuf *a, const void *data_)
geneve->len);
}

static void
erspan_to_attr(struct ofpbuf *a, const void *data_)
{
const struct erspan_metadata *md = data_;

nl_msg_put_unspec(a, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, md,
sizeof *md);
}

#define SCAN_PUT_ATTR(BUF, ATTR, DATA, FUNC) \
{ \
unsigned long call_fn = (unsigned long)FUNC; \
Expand Down Expand Up @@ -5253,6 +5403,8 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
SCAN_FIELD_NESTED("ttl=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TTL);
SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
SCAN_FIELD_NESTED_FUNC("erspan(", struct erspan_metadata, erspan_metadata,
erspan_to_attr);
SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
SCAN_FIELD_NESTED_FUNC("geneve(", struct geneve_scan, geneve,
geneve_to_attr);
Expand Down
25 changes: 24 additions & 1 deletion tests/odp.at
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,16 @@ sed 's/^/skb_priority(0),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt | s
echo
echo '# Valid forms with IP later fragment.'
sed 's/^/skb_priority(0),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt | sed -n 's/,frag=no),.*/,frag=later)/p'

echo
echo '# Valid forms with tunnel and ERSPAN v1 headers.'
sed
's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,ttl=128,erspan(ver=1,idx=0x7),flags(df|key)),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt

echo
echo '# Valid forms with tunnel and ERSPAN v2 headers.'
sed
's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,ttl=128,erspan(ver=2,dir=0x1,hwid=0x7),flags(df|key)),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt
) > odp-in.txt
AT_CAPTURE_FILE([odp-in.txt])

Expand Down Expand Up @@ -172,7 +182,18 @@ sed -n 's/,frag=no),/,frag=first),/p' odp-base.txt

echo
echo '# Valid forms with IP later fragment.'
sed -n 's/,frag=no),.*/,frag=later)/p' odp-base.txt) > odp.txt
sed -n 's/,frag=no),.*/,frag=later)/p' odp-base.txt

echo
echo '# Valid forms with tunnel and ERSPAN v1 headers.'
sed
's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,ttl=128,erspan(ver=1/0,idx=0x7/0xf),flags(df|key)),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt

echo
echo '# Valid forms with tunnel and ERSPAN v2 headers.'
sed
's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,ttl=128,erspan(ver=2,dir=0x1,hwid=0x7/0xf),flags(df|key)),skb_mark(0),recirc_id(0),dp_hash(0),/' odp-base.txt
) > odp.txt
AT_CAPTURE_FILE([odp.txt])
AT_CHECK_UNQUOTED([ovstest test-odp parse-wc-keys < odp.txt], [0], [`cat odp.txt`
])
Expand Down Expand Up @@ -358,6 +379,8 @@ ct_clear
trunc(100)
clone(1)
clone(clone(push_vlan(vid=12,pcp=0),2),1)
set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,erspan(ver=1,idx=0x7),flags(df|key)))
set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,erspan(ver=2,dir=1,hwid=0x1),flags(df|key)))
])
AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0],
[`cat actions.txt`
Expand Down
5 changes: 5 additions & 0 deletions tests/system-common-macros.at
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ m4_define([OVS_CHECK_GRE],
[AT_SKIP_IF([! ip link add foo type gretap help 2>&1 | grep gretap >/dev/null])
OVS_CHECK_FIREWALL()])

# OVS_CHECK_ERSPAN()
m4_define([OVS_CHECK_ERSPAN],
[AT_SKIP_IF([! ip link add foo type erspan help 2>&1 | grep erspan >/dev/null])
OVS_CHECK_FIREWALL()])

# OVS_CHECK_GRE_L3()
m4_define([OVS_CHECK_GRE_L3],
[AT_SKIP_IF([! ip link add foo type gre help 2>&1 | grep "gre " >/dev/null])
Expand Down
Loading

0 comments on commit 98514ee

Please sign in to comment.