2
0
mirror of https://github.com/openvswitch/ovs synced 2025-10-15 14:17:18 +00:00

Add connection tracking mark support.

This patch adds a new 32-bit metadata field to the connection tracking
interface. When a mark is specified as part of the ct action and the
connection is committed, the value is saved with the current connection.
Subsequent ct lookups with the table specified will expose this metadata
as the "ct_mark" field in the flow.

For example, to allow new TCP connections from port 1->2 and only allow
established connections from port 2->1, and to associate a mark with those
connections:

    table=0,priority=1,action=drop
    table=0,arp,action=normal
    table=0,in_port=1,tcp,action=ct(commit,exec(set_field:1->ct_mark)),2
    table=0,in_port=2,ct_state=-trk,tcp,action=ct(table=1)
    table=1,in_port=2,ct_state=+trk,ct_mark=1,tcp,action=1

Signed-off-by: Joe Stringer <joestringer@nicira.com>
Acked-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Joe Stringer
2015-09-18 13:58:00 -07:00
parent 07659514c3
commit 8e53fe8cf7
30 changed files with 550 additions and 43 deletions

View File

@@ -137,6 +137,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char *namebuf, size_t bufsize)
case OVS_KEY_ATTR_SKB_MARK: return "skb_mark";
case OVS_KEY_ATTR_CT_STATE: return "ct_state";
case OVS_KEY_ATTR_CT_ZONE: return "ct_zone";
case OVS_KEY_ATTR_CT_MARK: return "ct_mark";
case OVS_KEY_ATTR_TUNNEL: return "tunnel";
case OVS_KEY_ATTR_IN_PORT: return "in_port";
case OVS_KEY_ATTR_ETHERNET: return "eth";
@@ -538,14 +539,17 @@ format_odp_tnl_push_action(struct ds *ds, const struct nlattr *attr)
static const struct nl_policy ovs_conntrack_policy[] = {
[OVS_CT_ATTR_COMMIT] = { .type = NL_A_FLAG, .optional = true, },
[OVS_CT_ATTR_ZONE] = { .type = NL_A_U16, .optional = true, },
[OVS_CT_ATTR_MARK] = { .type = NL_A_UNSPEC, .optional = true,
.min_len = sizeof(uint32_t) * 2 },
};
static void
format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
{
struct nlattr *a[ARRAY_SIZE(ovs_conntrack_policy)];
bool commit;
const uint32_t *mark;
uint16_t zone;
bool commit;
if (!nl_parse_nested(attr, ovs_conntrack_policy, a, ARRAY_SIZE(a))) {
ds_put_cstr(ds, "ct(error)");
@@ -554,9 +558,10 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
commit = a[OVS_CT_ATTR_COMMIT] ? true : false;
zone = a[OVS_CT_ATTR_ZONE] ? nl_attr_get_u16(a[OVS_CT_ATTR_ZONE]) : 0;
mark = a[OVS_CT_ATTR_MARK] ? nl_attr_get(a[OVS_CT_ATTR_MARK]) : NULL;
ds_put_format(ds, "ct");
if (commit || zone) {
if (commit || zone || mark) {
ds_put_cstr(ds, "(");
if (commit) {
ds_put_format(ds, "commit,");
@@ -564,6 +569,10 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
if (zone) {
ds_put_format(ds, "zone=%"PRIu16",", zone);
}
if (mark) {
ds_put_format(ds, "mark=%#"PRIx32"/%#"PRIx32",", *mark,
*(mark + 1));
}
ds_chomp(ds, ',');
ds_put_cstr(ds, ")");
}
@@ -1007,6 +1016,10 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
if (ovs_scan(s, "ct")) {
bool commit = false;
uint16_t zone = 0;
struct {
uint32_t value;
uint32_t mask;
} ct_mark = { 0, 0 };
size_t start;
char *end;
@@ -1031,6 +1044,16 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
s += n;
continue;
}
if (ovs_scan(s, "mark=%"SCNx32"%n", &ct_mark.value, &n)) {
s += n;
n = -1;
if (ovs_scan(s, "/%"SCNx32"%n", &ct_mark.mask, &n)) {
s += n;
} else {
ct_mark.mask = UINT32_MAX;
}
continue;
}
return -EINVAL;
}
@@ -1044,6 +1067,10 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
if (zone) {
nl_msg_put_u16(actions, OVS_CT_ATTR_ZONE, zone);
}
if (ct_mark.mask) {
nl_msg_put_unspec(actions, OVS_CT_ATTR_MARK, &ct_mark,
sizeof(ct_mark));
}
nl_msg_end_nested(actions, start);
}
@@ -1313,6 +1340,7 @@ static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] =
[OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) },
[OVS_KEY_ATTR_CT_STATE] = { .len = 4 },
[OVS_KEY_ATTR_CT_ZONE] = { .len = 2 },
[OVS_KEY_ATTR_CT_MARK] = { .len = 4 },
};
/* Returns the correct length of the payload for a flow key attribute of the
@@ -2195,6 +2223,15 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
}
break;
case OVS_KEY_ATTR_CT_MARK:
if (verbose || !mask_empty(ma)) {
ds_put_format(ds, "%#"PRIx32, nl_attr_get_u32(a));
if (!is_exact) {
ds_put_format(ds, "/%#"PRIx32, nl_attr_get_u32(ma));
}
}
break;
case OVS_KEY_ATTR_CT_STATE:
if (verbose) {
ds_put_format(ds, "%#"PRIx32, nl_attr_get_u32(a));
@@ -3388,6 +3425,7 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
SCAN_SINGLE("ct_state(", uint32_t, ct_state, OVS_KEY_ATTR_CT_STATE);
SCAN_SINGLE("ct_zone(", uint16_t, u16, OVS_KEY_ATTR_CT_ZONE);
SCAN_SINGLE("ct_mark(", uint32_t, u32, OVS_KEY_ATTR_CT_MARK);
SCAN_BEGIN_NESTED("tunnel(", OVS_KEY_ATTR_TUNNEL) {
SCAN_FIELD_NESTED("tun_id=", ovs_be64, be64, OVS_TUNNEL_KEY_ATTR_ID);
@@ -3630,6 +3668,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
if (parms->support.ct_zone) {
nl_msg_put_u16(buf, OVS_KEY_ATTR_CT_ZONE, data->ct_zone);
}
if (parms->support.ct_mark) {
nl_msg_put_u32(buf, OVS_KEY_ATTR_CT_MARK, data->ct_mark);
}
if (parms->support.recirc) {
nl_msg_put_u32(buf, OVS_KEY_ATTR_RECIRC_ID, data->recirc_id);
nl_msg_put_u32(buf, OVS_KEY_ATTR_DP_HASH, data->dp_hash);
@@ -3818,6 +3859,9 @@ odp_key_from_pkt_metadata(struct ofpbuf *buf, const struct pkt_metadata *md)
if (md->ct_zone) {
nl_msg_put_u16(buf, OVS_KEY_ATTR_CT_ZONE, md->ct_zone);
}
if (md->ct_mark) {
nl_msg_put_u32(buf, OVS_KEY_ATTR_CT_MARK, md->ct_mark);
}
}
/* Add an ingress port attribute if 'odp_in_port' is not the magical
@@ -3875,6 +3919,10 @@ odp_key_to_pkt_metadata(const struct nlattr *key, size_t key_len,
md->ct_zone = nl_attr_get_u16(nla);
wanted_attrs &= ~(1u << OVS_KEY_ATTR_CT_ZONE);
break;
case OVS_KEY_ATTR_CT_MARK:
md->ct_mark = nl_attr_get_u32(nla);
wanted_attrs &= ~(1u << OVS_KEY_ATTR_CT_MARK);
break;
case OVS_KEY_ATTR_TUNNEL: {
enum odp_key_fitness res;
@@ -4439,6 +4487,10 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len,
flow->ct_zone = nl_attr_get_u16(attrs[OVS_KEY_ATTR_CT_ZONE]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_CT_ZONE;
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_CT_MARK)) {
flow->ct_mark = nl_attr_get_u32(attrs[OVS_KEY_ATTR_CT_MARK]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_CT_MARK;
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUNNEL)) {
enum odp_key_fitness res;