diff options
author | Paul Blakey <paulb@mellanox.com> | 2019-12-22 12:16:43 +0200 |
---|---|---|
committer | Simon Horman <simon.horman@netronome.com> | 2019-12-22 11:54:41 +0100 |
commit | 2bf6ffb76ac6e8ae23df8bde72d85c2b351d1160 (patch) | |
tree | 25fc5f4de18b8aa7399f131fc972ab476fe69dbb /lib | |
parent | 9221c721bec076a6b89d3d9b84fe7d87bf7ee134 (diff) | |
download | openvswitch-2bf6ffb76ac6e8ae23df8bde72d85c2b351d1160.tar.gz |
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>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/netdev-offload-tc.c | 105 | ||||
-rw-r--r-- | lib/tc.c | 93 | ||||
-rw-r--r-- | lib/tc.h | 28 |
3 files changed, 226 insertions, 0 deletions
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c index f9b0d34f0..9e1c84d44 100644 --- a/lib/netdev-offload-tc.c +++ b/lib/netdev-offload-tc.c @@ -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; @@ -907,6 +941,66 @@ parse_mpls_set_action(struct tc_flower *flower, struct tc_action *action, } 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, const struct nlattr *ct, @@ -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; @@ -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; } @@ -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; |