2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

netdev-offload-tc: Add conntrack nat support

Signed-off-by: Paul Blakey <paulb@mellanox.com>
Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
Paul Blakey
2019-12-22 12:16:43 +02:00
committed by Simon Horman
parent 9221c721be
commit 2bf6ffb76a
3 changed files with 226 additions and 0 deletions

View File

@@ -815,6 +815,40 @@ parse_tc_flower_to_match(struct tc_flower *flower,
ct_label->mask = action->ct.label_mask;
}
if (action->ct.nat_type) {
size_t nat_offset = nl_msg_start_nested(buf,
OVS_CT_ATTR_NAT);
if (action->ct.nat_type == TC_NAT_SRC) {
nl_msg_put_flag(buf, OVS_NAT_ATTR_SRC);
} else if (action->ct.nat_type == TC_NAT_DST) {
nl_msg_put_flag(buf, OVS_NAT_ATTR_DST);
}
if (action->ct.range.ip_family == AF_INET) {
nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MIN,
action->ct.range.ipv4.min);
nl_msg_put_be32(buf, OVS_NAT_ATTR_IP_MAX,
action->ct.range.ipv4.max);
} else if (action->ct.range.ip_family == AF_INET6) {
nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MIN,
&action->ct.range.ipv6.min);
nl_msg_put_in6_addr(buf, OVS_NAT_ATTR_IP_MAX,
&action->ct.range.ipv6.max);
}
if (action->ct.range.port.min) {
nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MIN,
ntohs(action->ct.range.port.min));
if (action->ct.range.port.max) {
nl_msg_put_u16(buf, OVS_NAT_ATTR_PROTO_MAX,
ntohs(action->ct.range.port.max));
}
}
nl_msg_end_nested(buf, nat_offset);
}
nl_msg_end_nested(buf, ct_offset);
}
break;
@@ -906,6 +940,66 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action,
return 0;
}
static int
parse_put_flow_nat_action(struct tc_action *action,
const struct nlattr *nat,
size_t nat_len)
{
const struct nlattr *nat_attr;
size_t nat_left;
action->ct.nat_type = TC_NAT_RESTORE;
NL_ATTR_FOR_EACH_UNSAFE (nat_attr, nat_left, nat, nat_len) {
switch (nl_attr_type(nat_attr)) {
case OVS_NAT_ATTR_SRC: {
action->ct.nat_type = TC_NAT_SRC;
};
break;
case OVS_NAT_ATTR_DST: {
action->ct.nat_type = TC_NAT_DST;
};
break;
case OVS_NAT_ATTR_IP_MIN: {
if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) {
ovs_be32 addr = nl_attr_get_be32(nat_attr);
action->ct.range.ipv4.min = addr;
action->ct.range.ip_family = AF_INET;
} else {
struct in6_addr addr = nl_attr_get_in6_addr(nat_attr);
action->ct.range.ipv6.min = addr;
action->ct.range.ip_family = AF_INET6;
}
};
break;
case OVS_NAT_ATTR_IP_MAX: {
if (nl_attr_get_size(nat_attr) == sizeof(ovs_be32)) {
ovs_be32 addr = nl_attr_get_be32(nat_attr);
action->ct.range.ipv4.max = addr;
action->ct.range.ip_family = AF_INET;
} else {
struct in6_addr addr = nl_attr_get_in6_addr(nat_attr);
action->ct.range.ipv6.max = addr;
action->ct.range.ip_family = AF_INET6;
}
};
break;
case OVS_NAT_ATTR_PROTO_MIN: {
action->ct.range.port.min = htons(nl_attr_get_u16(nat_attr));
};
break;
case OVS_NAT_ATTR_PROTO_MAX: {
action->ct.range.port.max = htons(nl_attr_get_u16(nat_attr));
};
break;
}
}
return 0;
}
static int
parse_put_flow_ct_action(struct tc_flower *flower,
struct tc_action *action,
@@ -914,6 +1008,7 @@ parse_put_flow_ct_action(struct tc_flower *flower,
{
const struct nlattr *ct_attr;
size_t ct_left;
int err;
NL_ATTR_FOR_EACH_UNSAFE (ct_attr, ct_left, ct, ct_len) {
switch (nl_attr_type(ct_attr)) {
@@ -925,6 +1020,16 @@ parse_put_flow_ct_action(struct tc_flower *flower,
action->ct.zone = nl_attr_get_u16(ct_attr);
}
break;
case OVS_CT_ATTR_NAT: {
const struct nlattr *nat = nl_attr_get(ct_attr);
const size_t nat_len = nl_attr_get_size(ct_attr);
err = parse_put_flow_nat_action(action, nat, nat_len);
if (err) {
return err;
}
}
break;
case OVS_CT_ATTR_MARK: {
const struct {
uint32_t key;

View File

@@ -1288,6 +1288,20 @@ static const struct nl_policy ct_policy[] = {
.optional = true, },
[TCA_CT_LABELS_MASK] = { .type = NL_A_UNSPEC,
.optional = true, },
[TCA_CT_NAT_IPV4_MIN] = { .type = NL_A_U32,
.optional = true, },
[TCA_CT_NAT_IPV4_MAX] = { .type = NL_A_U32,
.optional = true, },
[TCA_CT_NAT_IPV6_MIN] = { .min_len = sizeof(struct in6_addr),
.type = NL_A_UNSPEC,
.optional = true },
[TCA_CT_NAT_IPV6_MAX] = { .min_len = sizeof(struct in6_addr),
.type = NL_A_UNSPEC,
.optional = true },
[TCA_CT_NAT_PORT_MIN] = { .type = NL_A_U16,
.optional = true, },
[TCA_CT_NAT_PORT_MAX] = { .type = NL_A_U16,
.optional = true, },
};
static int
@@ -1331,6 +1345,47 @@ nl_parse_act_ct(struct nlattr *options, struct tc_flower *flower)
action->ct.label_mask = label_mask ?
nl_attr_get_u128(label_mask) : OVS_U128_ZERO;
if (ct_action & TCA_CT_ACT_NAT) {
struct nlattr *ipv4_min = ct_attrs[TCA_CT_NAT_IPV4_MIN];
struct nlattr *ipv4_max = ct_attrs[TCA_CT_NAT_IPV4_MAX];
struct nlattr *ipv6_min = ct_attrs[TCA_CT_NAT_IPV6_MIN];
struct nlattr *ipv6_max = ct_attrs[TCA_CT_NAT_IPV6_MAX];
struct nlattr *port_min = ct_attrs[TCA_CT_NAT_PORT_MIN];
struct nlattr *port_max = ct_attrs[TCA_CT_NAT_PORT_MAX];
action->ct.nat_type = TC_NAT_RESTORE;
if (ct_action & TCA_CT_ACT_NAT_SRC) {
action->ct.nat_type = TC_NAT_SRC;
} else if (ct_action & TCA_CT_ACT_NAT_DST) {
action->ct.nat_type = TC_NAT_DST;
}
if (ipv4_min) {
action->ct.range.ip_family = AF_INET;
action->ct.range.ipv4.min = nl_attr_get_be32(ipv4_min);
if (ipv4_max) {
ovs_be32 addr = nl_attr_get_be32(ipv4_max);
action->ct.range.ipv4.max = addr;
}
} else if (ipv6_min) {
action->ct.range.ip_family = AF_INET6;
action->ct.range.ipv6.min
= nl_attr_get_in6_addr(ipv6_min);
if (ipv6_max) {
struct in6_addr addr = nl_attr_get_in6_addr(ipv6_max);
action->ct.range.ipv6.max = addr;
}
}
if (port_min) {
action->ct.range.port.min = nl_attr_get_be16(port_min);
if (port_max) {
action->ct.range.port.max = nl_attr_get_be16(port_max);
}
}
}
}
action->type = TC_ACT_CT;
@@ -2062,6 +2117,44 @@ nl_msg_put_act_ct(struct ofpbuf *request, struct tc_action *action)
ct_action |= TCA_CT_ACT_FORCE;
}
}
if (action->ct.nat_type) {
ct_action |= TCA_CT_ACT_NAT;
if (action->ct.nat_type == TC_NAT_SRC) {
ct_action |= TCA_CT_ACT_NAT_SRC;
} else if (action->ct.nat_type == TC_NAT_DST) {
ct_action |= TCA_CT_ACT_NAT_DST;
}
if (action->ct.range.ip_family == AF_INET) {
nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MIN,
action->ct.range.ipv4.min);
if (action->ct.range.ipv4.max) {
nl_msg_put_be32(request, TCA_CT_NAT_IPV4_MAX,
action->ct.range.ipv4.max);
}
} else if (action->ct.range.ip_family == AF_INET6) {
size_t ipv6_sz = sizeof(action->ct.range.ipv6.max);
nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MIN,
&action->ct.range.ipv6.min);
if (!is_all_zeros(&action->ct.range.ipv6.max,
ipv6_sz)) {
nl_msg_put_in6_addr(request, TCA_CT_NAT_IPV6_MAX,
&action->ct.range.ipv6.max);
}
}
if (action->ct.range.port.min) {
nl_msg_put_be16(request, TCA_CT_NAT_PORT_MIN,
action->ct.range.port.min);
if (action->ct.range.port.max) {
nl_msg_put_be16(request, TCA_CT_NAT_PORT_MAX,
action->ct.range.port.max);
}
}
}
} else {
ct_action = TCA_CT_ACT_CLEAR;
}

View File

@@ -165,6 +165,13 @@ enum tc_action_type {
TC_ACT_CT,
};
enum nat_type {
TC_NO_NAT = 0,
TC_NAT_SRC,
TC_NAT_DST,
TC_NAT_RESTORE,
};
struct tc_action {
union {
int chain;
@@ -213,6 +220,27 @@ struct tc_action {
uint32_t mark_mask;
ovs_u128 label;
ovs_u128 label_mask;
uint8_t nat_type;
struct {
uint8_t ip_family;
union {
struct {
ovs_be32 min;
ovs_be32 max;
} ipv4;
struct {
struct in6_addr min;
struct in6_addr max;
} ipv6;
};
union {
ovs_be16 min;
ovs_be16 max;
} port;
} range;
bool clear;
bool force;
bool commit;