WIP --- lib/dpif-netdev.c | 1 + lib/dpif.c | 1 + lib/odp-execute.c | 1 + lib/odp-util.c | 113 +++++++++++++++++++++++++++++++++++++++++++ lib/ofp-actions.c | 104 +++++++++++++++++++++++++++++++++++++++ lib/ofp-actions.h | 22 +++++++++ ofproto/ofproto-dpif-xlate.c | 21 ++++++++ 7 files changed, 263 insertions(+)
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 82dbfd0..a2f9e71 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -2908,6 +2908,7 @@ dp_execute_cb(void *aux_, struct dpif_packet **packets, int cnt, case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case OVS_ACTION_ATTR_CONNTRACK: + case OVS_ACTION_ATTR_NAT: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/dpif.c b/lib/dpif.c index bdb0564..c63f3f3 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -1045,6 +1045,7 @@ dpif_execute_helper_cb(void *aux_, struct dpif_packet **packets, int cnt, case OVS_ACTION_ATTR_SAMPLE: case OVS_ACTION_ATTR_UNSPEC: case OVS_ACTION_ATTR_CONNTRACK: + case OVS_ACTION_ATTR_NAT: case __OVS_ACTION_ATTR_MAX: OVS_NOT_REACHED(); } diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 59ce7e3..ae346e8 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -529,6 +529,7 @@ odp_execute_actions__(void *dp, struct dpif_packet **packets, int cnt, break; case OVS_ACTION_ATTR_CONNTRACK: + case OVS_ACTION_ATTR_NAT: /* xxx I don't think there's anything we can do here. */ break; diff --git a/lib/odp-util.c b/lib/odp-util.c index 061c8d6..205a186 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -85,6 +85,7 @@ odp_action_len(uint16_t type) case OVS_ACTION_ATTR_SET_MASKED: return -2; case OVS_ACTION_ATTR_SAMPLE: return -2; case OVS_ACTION_ATTR_CONNTRACK: return -2; + case OVS_ACTION_ATTR_NAT: return -2; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: @@ -526,6 +527,90 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr) } static void +format_odp_nat_action(struct ds *ds, const struct nlattr *attr) +{ + static const struct nl_policy ovs_nat_policy[] = { + [OVS_NAT_ATTR_TYPE] = { .type = NL_A_U32 }, + [OVS_NAT_ATTR_IP_MIN] = { .type = NL_A_U32, + .optional = true, }, + [OVS_NAT_ATTR_IP_MAX] = { .type = NL_A_U32, + .optional = true, }, + [OVS_NAT_ATTR_PROTO_MIN] = { .type = NL_A_U16, + .optional = true, }, + [OVS_NAT_ATTR_PROTO_MAX] = { .type = NL_A_U16, + .optional = true, }, + [OVS_NAT_ATTR_FLAGS] = { .type = NL_A_U32, + .optional = true, }, + }; + struct nlattr *a[ARRAY_SIZE(ovs_nat_policy)]; + ovs_be32 ip_min = 0, ip_max = 0; + ovs_be16 proto_min = 0, proto_max = 0; + uint32_t type, flags = 0; + + if (!nl_parse_nested(attr, ovs_nat_policy, a, ARRAY_SIZE(a))) { + ds_put_cstr(ds, "nat(error)"); + return; + } + + type = nl_attr_get_u32(a[OVS_NAT_ATTR_TYPE]); + + if (a[OVS_NAT_ATTR_IP_MIN]) { + ip_min = nl_attr_get_be32(a[OVS_NAT_ATTR_IP_MIN]); + } + + if (a[OVS_NAT_ATTR_IP_MAX]) { + ip_max = nl_attr_get_be32(a[OVS_NAT_ATTR_IP_MAX]); + } + + if (a[OVS_NAT_ATTR_PROTO_MIN]) { + proto_min = nl_attr_get_be16(a[OVS_NAT_ATTR_PROTO_MIN]); + } + + if (a[OVS_NAT_ATTR_PROTO_MAX]) { + proto_max = nl_attr_get_be16(a[OVS_NAT_ATTR_PROTO_MAX]); + } + + if (a[OVS_NAT_ATTR_FLAGS]) { + flags = nl_attr_get_u32(a[OVS_NAT_ATTR_FLAGS]); + } + + ds_put_format(ds, "nat(type=%u", type); + + if (ip_min) { + ds_put_format(ds, ",ip_min="IP_FMT, IP_ARGS(ip_min)); + + if (ip_min != ip_max) { + ds_put_format(ds, ",ip_max="IP_FMT, IP_ARGS(ip_max)); + } + } + + if (proto_min) { + ds_put_format(ds, ":%"PRIu16, proto_min); + + if (proto_min != proto_max) { + ds_put_format(ds, "-%"PRIu16, proto_min); + } + } + + if (flags) { + ds_put_format(ds, ",flags="); + if (flags & OVS_NAT_FLAG_PERSISTENT) { + ds_put_format(ds, ",persistent"); + } + + if (flags & OVS_NAT_FLAG_PROTO_RAND) { + ds_put_format(ds, ",hash-map"); + } + + if (flags & OVS_NAT_FLAG_PROTO_FULL_RAND) { + ds_put_format(ds, ",random"); + } + } + + ds_put_format(ds, ")"); +} + +static void format_odp_action(struct ds *ds, const struct nlattr *a) { int expected_len; @@ -612,6 +697,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a) format_odp_conntrack_action(ds,a); break; } + case OVS_ACTION_ATTR_NAT: + format_odp_nat_action(ds, a); + break; case OVS_ACTION_ATTR_UNSPEC: case __OVS_ACTION_ATTR_MAX: default: @@ -915,6 +1003,31 @@ parse_odp_action(const char *s, const struct simap *port_names, } } + { + ovs_be32 ip_min = 0, ip_max = 0; + size_t nat_ofs; + int n = -1, flags = 0, type; + + if (ovs_scan(s, "nat(type=%i,ip_min="IP_SCAN_FMT",ip_max="IP_SCAN_FMT",flags=%i)%n", + &type, IP_SCAN_ARGS(&ip_min), IP_SCAN_ARGS(&ip_max), &flags, &n)) { + + nat_ofs = nl_msg_start_nested(actions, OVS_ACTION_ATTR_NAT); + + /* FIXME: Add correct parsers */ + nl_msg_put_u32(actions, OVS_NAT_ATTR_TYPE, type); + + if (ip_min) { + nl_msg_put_be32(actions, OVS_NAT_ATTR_IP_MIN, ip_min); + nl_msg_put_be32(actions, OVS_NAT_ATTR_IP_MAX, ip_max); + } + + nl_msg_end_nested(actions, nat_ofs); + + return n; + + } + } + return -EINVAL; } diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 0ab8a94..720bc45 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -270,6 +270,9 @@ enum ofp_raw_action_type { /* NX1.0+(32): struct nx_action_conntrack. */ NXAST_RAW_CONNTRACK, + + /* NX1.0+(33): struct nx_action_nat. */ + NXAST_RAW_NAT, }; /* OpenFlow actions are always a multiple of 8 bytes in length. */ @@ -4007,6 +4010,100 @@ format_CONNTRACK(const struct ofpact_conntrack *a, struct ds *s) a->flags, a->zone); } +/* Action structure for NXAST_NAT. + * + * Perform stateful network address translation. + * Pass traffic to the connection tracker. If 'flags' is + * NX_CONNTRACK_F_RECIRC, traffic is recirculated back to flow table + * with the NXM_NX_CONN_STATE and NXM_NX_CONN_STATE_W matches set. A + * standard "resubmit" action is not sufficient, since connection + * tracking occurs outside of the classifier. The 'zone' argument + * specifies a context within which the tracking is done. */ +struct nx_action_nat { + ovs_be16 type; /* OFPAT_VENDOR. */ + ovs_be16 len; /* 16. */ + ovs_be32 vendor; /* NX_VENDOR_ID. */ + ovs_be16 subtype; /* NXAST_NAT. */ + ovs_be16 flags; /* Either 0 or NX_CONNTRACK_F_RECIRC. */ + ovs_be32 nat_type; /* NAT type */ + ovs_be32 ip_min; /* Minimum IP range */ + ovs_be32 ip_max; /* Maximum IP range */ + ovs_be16 proto_min; /* Minimum L4 protocol range */ + ovs_be16 proto_max; /* Maximum L4 protocol range */ + uint8_t pad[4]; +}; +OFP_ASSERT(sizeof(struct nx_action_nat) == 32); + +static enum ofperr +decode_NXAST_RAW_NAT(const struct nx_action_nat *nan, + struct ofpbuf *out) +{ + struct ofpact_nat *nat; + + nat = ofpact_put_NAT(out); + nat->flags = ntohs(nan->flags); + nat->nat_type = ntohl(nan->nat_type); + nat->ip_min = nan->ip_min; + nat->ip_max = nan->ip_max; + + return 0; +} + +static void +encode_NAT(const struct ofpact_nat *nat, + enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out) +{ + struct nx_action_nat *nan; + + nan = put_NXAST_NAT(out); + nan->flags = htons(nat->flags); + nan->nat_type = htonl(nat->nat_type); + nan->ip_min = nat->ip_min; + nan->ip_max = nat->ip_max; +} + +/* Parses 'arg' as the argument to a "nat" action, and appends such an + * action to 'ofpacts'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +static char * WARN_UNUSED_RESULT +parse_NAT(char *arg, struct ofpbuf *ofpacts, + enum ofputil_protocol *usable_protocols OVS_UNUSED) +{ + struct ofpact_nat *on = ofpact_put_NAT(ofpacts); + char *key, *value; + + while (ofputil_parse_key_value(&arg, &key, &value)) { + char *error = NULL; + + if (!strcmp(key, "type")) { + error = str_to_u32(value, &on->nat_type); + } else if (!strcmp(key, "flags")) { + error = str_to_u16(value, "flags", &on->flags); + } else if (!strcmp(key, "ip_min")) { + error = str_to_ip(value, &on->ip_min); + } else if (!strcmp(key, "ip_max")) { + error = str_to_ip(value, &on->ip_max); + } else { + error = xasprintf("invalid key \"%s\" in \"nat\" argument", + key); + } + if (error) { + return error; + } + } + return NULL; +} + +static void +format_NAT(const struct ofpact_nat *a, struct ds *s) +{ + ds_put_format(s, "nat(type=%"PRIu32",ip_min="IP_FMT"," \ + "ip_max="IP_FMT",flags=%"PRIu16")", + a->nat_type, IP_ARGS(a->ip_min), IP_ARGS(a->ip_max), a->flags); +} + /* Meter instruction. */ static void @@ -4388,6 +4485,7 @@ ofpact_is_set_or_move_action(const struct ofpact *a) case OFPACT_BUNDLE: case OFPACT_CLEAR_ACTIONS: case OFPACT_CONNTRACK: + case OFPACT_NAT: case OFPACT_CONTROLLER: case OFPACT_DEC_MPLS_TTL: case OFPACT_DEC_TTL: @@ -4461,6 +4559,7 @@ ofpact_is_allowed_in_actions_set(const struct ofpact *a) case OFPACT_BUNDLE: case OFPACT_CONTROLLER: case OFPACT_CONNTRACK: + case OFPACT_NAT: case OFPACT_ENQUEUE: case OFPACT_EXIT: case OFPACT_FIN_TIMEOUT: @@ -4686,6 +4785,7 @@ ovs_instruction_type_from_ofpact_type(enum ofpact_type type) case OFPACT_EXIT: case OFPACT_SAMPLE: case OFPACT_CONNTRACK: + case OFPACT_NAT: default: return OVSINST_OFPIT11_APPLY_ACTIONS; } @@ -5250,6 +5350,9 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, case OFPACT_CONNTRACK: return 0; + case OFPACT_NAT: + return 0; + case OFPACT_CLEAR_ACTIONS: return 0; @@ -5670,6 +5773,7 @@ ofpact_outputs_to_port(const struct ofpact *ofpact, ofp_port_t port) case OFPACT_METER: case OFPACT_GROUP: case OFPACT_CONNTRACK: + case OFPACT_NAT: default: return false; } diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index a3a4b41..66754f5 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -106,6 +106,7 @@ OFPACT(EXIT, ofpact_null, ofpact, "exit") \ OFPACT(SAMPLE, ofpact_sample, ofpact, "sample") \ OFPACT(CONNTRACK, ofpact_conntrack, ofpact, "conntrack") \ + OFPACT(NAT, ofpact_nat, ofpact, "nat") \ \ /* Instructions. */ \ OFPACT(METER, ofpact_meter, ofpact, "meter") \ @@ -490,6 +491,27 @@ struct ofpact_conntrack { uint16_t zone; }; +/* Bits for 'flags' in struct nx_action_nat. + */ +enum nx_nat_flags { + NX_NAT_F_PERSISTENT = 1 << 0, + NX_NAT_F_PROTO_RAND = 1 << 1, + NX_NAT_F_PROTO_FULL_RAND = 1 << 2, +}; + +/* OFPACT_NAT. + * + * Used for NXAST_NAT. */ +struct ofpact_nat { + struct ofpact ofpact; + uint32_t nat_type; + ovs_be32 ip_min; + ovs_be32 ip_max; + ovs_be16 proto_min; + ovs_be16 proto_max; + uint16_t flags; +}; + static inline size_t ofpact_nest_get_action_len(const struct ofpact_nest *on) { diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index bb187a1..a341c84 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -3591,6 +3591,7 @@ ofpact_needs_recirculation_after_mpls(const struct xlate_ctx *ctx, case OFPACT_CLEAR_ACTIONS: case OFPACT_SAMPLE: case OFPACT_CONNTRACK: + case OFPACT_NAT: return false; case OFPACT_SET_IPV4_SRC: @@ -3652,6 +3653,22 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) } static void +compose_nat_action(struct xlate_ctx *ctx, struct ofpact_nat *ofn) +{ + size_t nat_offset; + struct ofpbuf *odp_actions = ctx->xout->odp_actions; + + nat_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_NAT); + nl_msg_put_u32(odp_actions, OVS_NAT_ATTR_TYPE, ofn->nat_type); + nl_msg_put_u32(odp_actions, OVS_NAT_ATTR_IP_MIN, ofn->ip_min); + nl_msg_put_u32(odp_actions, OVS_NAT_ATTR_IP_MAX, ofn->ip_max); + nl_msg_put_u16(odp_actions, OVS_NAT_ATTR_PROTO_MIN, ofn->proto_min); + nl_msg_put_u16(odp_actions, OVS_NAT_ATTR_PROTO_MIN, ofn->proto_max); + nl_msg_put_u32(odp_actions, OVS_NAT_ATTR_FLAGS, ofn->flags); + nl_msg_end_nested(odp_actions, nat_offset); +} + +static void do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, struct xlate_ctx *ctx) { @@ -3957,6 +3974,10 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, case OFPACT_CONNTRACK: compose_conntrack_action(ctx, ofpact_get_CONNTRACK(a)); break; + + case OFPACT_NAT: + compose_nat_action(ctx, ofpact_get_NAT(a)); + break; } } } -- 1.9.3 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev