[ovs-dev] [PATCH 1/1] Implement DNAT based on destnation port
Guru Shetty
guru at ovn.org
Wed Mar 1 17:09:56 UTC 2017
On 28 February 2017 at 19:16, lg.yue <kernelluck at 163.com> wrote:
> Add support for dnat based on destnation port.
>
A DNAT with a destination port is the same as a Load Balancer with a single
endpoint. Load balancer supports adding ports. Can you try using it and
tell what is it that it lacks?
>
> From 0dd41ed18d520c6d61bc23c5fefad5132aa9dadd Mon Sep 17 00:00:00 2001
> From: "lg.yue" <yuelongguang at gmail.com>
> Date: Wed, 1 Mar 2017 11:07:16 +0800
> Subject: [PATCH 1/1] Implement DNAT based on destnation port
>
> Signed-off-by: lg.yue <yuelongguang at gmail.com>
> ---
> include/ovn/actions.h | 1 +
> ovn/lib/actions.c | 11 +++++++
> ovn/lib/lex.c | 8 +++++
> ovn/northd/ovn-northd.c | 24 +++++++++++---
> ovn/ovn-nb.ovsschema | 6 ++--
> ovn/ovn-nb.xml | 18 ++++++++++
> ovn/utilities/ovn-nbctl.c | 83 ++++++++++++++++++++++++++++++
> ++++-------------
> 7 files changed, 122 insertions(+), 29 deletions(-)
>
> diff --git a/include/ovn/actions.h b/include/ovn/actions.h
> index d2510fd..f4a9780 100644
> --- a/include/ovn/actions.h
> +++ b/include/ovn/actions.h
> @@ -194,6 +194,7 @@ struct ovnact_ct_commit {
> struct ovnact_ct_nat {
> struct ovnact ovnact;
> ovs_be32 ip;
> + uint16_t port;
> uint8_t ltable; /* Logical table ID of next table. */
> };
>
> diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
> index fff838b..3b8ed28 100644
> --- a/ovn/lib/actions.c
> +++ b/ovn/lib/actions.c
> @@ -746,6 +746,14 @@ parse_ct_nat(struct action_context *ctx, const char
> *name,
> cn->ip = ctx->lexer->token.value.ipv4;
> lexer_get(ctx->lexer);
>
> + /* Parse optional port. */
> + uint16_t port = 0;
> + if (lexer_match(ctx->lexer, LEX_T_COLON)
> + && !action_parse_port(ctx, &port)) {
> + return;
> + }
> + cn->port = port;
> +
> if (!lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
> return;
> }
> @@ -822,6 +830,9 @@ encode_ct_nat(const struct ovnact_ct_nat *cn,
> nat->flags |= NX_NAT_F_SRC;
> } else {
> nat->flags |= NX_NAT_F_DST;
> + if (cn->port) {
> + nat->range.proto.min = cn->port;
> + }
> }
> }
>
> diff --git a/ovn/lib/lex.c b/ovn/lib/lex.c
> index 4b504cb..9937d9d 100644
> --- a/ovn/lib/lex.c
> +++ b/ovn/lib/lex.c
> @@ -417,6 +417,14 @@ lex_parse_integer__(const char *p, struct lex_token
> *token)
> char copy[INET6_ADDRSTRLEN];
> memcpy(copy, p, len);
> copy[len] = '\0';
> +
> + if (strchr(copy, '.') && strchr(copy, ':')) {
> + char *ps = strchr(copy, ':');
> + int l;
> + l = ps - p;
> + copy[l] = '\0';
> + end = p + l;
> + }
>
> if (ip_parse(copy, &token->value.ipv4)) {
> token->format = LEX_F_IPV4;
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index 03dc850..688c1b7 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -1177,7 +1177,6 @@ tag_alloc_create_new_tag(struct hmap
> *tag_alloc_table,
> nbrec_logical_switch_port_set_tag(nbsp, nbsp->tag_request, 1);
> }
> }
> -
>
> /*
> * This function checks if the MAC in "address" parameter (if present) is
> @@ -4355,6 +4354,7 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
> /* Ingress DNAT table: Packets enter the pipeline with
> destination
> * IP address that needs to be DNATted from a external IP
> address
> * to a logical IP address. */
> + int dnat = 0, pro = 100;
> if (!strcmp(nat->type, "dnat")
> || !strcmp(nat->type, "dnat_and_snat")) {
> if (!od->l3dgw_port) {
> @@ -4365,6 +4365,17 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
> ds_clear(&match);
> ds_put_format(&match, "ip && ip4.dst == %s",
> nat->external_ip);
> + if(!strcmp(nat->type, "dnat")){
> + if(nat->eport && nat->protocol){
> + if(!strcmp(nat->protocol, "tcp")) {
> + ds_put_format(&match, " && tcp && tcp.dst
> == %d", (short int)nat->eport);
> + dnat = 1;
> + } else if (!strcmp(nat->protocol, "udp")) {
> + ds_put_format(&match, " && udp && udp.dst
> == %d", (short int)nat->eport);
> + dnat = 1;
> + } else { continue; }
> + } else { ;}
> + }
> ds_clear(&actions);
> if (dnat_force_snat_ip) {
> /* Indicate to the future tables that a DNAT has
> taken
> @@ -4373,9 +4384,14 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
> ds_put_format(&actions,
> "flags.force_snat_for_dnat = 1; ");
> }
> - ds_put_format(&actions, "flags.loopback = 1;
> ct_dnat(%s);",
> - nat->logical_ip);
> - ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, 100,
> +
> + if(dnat) {
> + pro = 90;
> + ds_put_format(&actions, "flags.loopback = 1;
> ct_dnat(%s:%d);", nat->logical_ip, (short int)(nat->lport?:nat->eport));
> + } else {
> + ds_put_format(&actions, "flags.loopback = 1;
> ct_dnat(%s);", nat->logical_ip);
> + }
> + ovn_lflow_add(lflows, od, S_ROUTER_IN_DNAT, pro,
> ds_cstr(&match), ds_cstr(&actions));
> } else {
> /* Distributed router. */
> diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema
> index dd0ac3d..21bf29a 100644
> --- a/ovn/ovn-nb.ovsschema
> +++ b/ovn/ovn-nb.ovsschema
> @@ -1,7 +1,7 @@
> {
> "name": "OVN_Northbound",
> "version": "5.5.0",
> - "cksum": "2099428463 14236",
> + "cksum": "1556209089 14350",
> "tables": {
> "NB_Global": {
> "columns": {
> @@ -229,7 +229,9 @@
> "enum": ["set", ["dnat",
> "snat",
>
> "dnat_and_snat"
> - ]]}}}},
> + ]]}}},
> + "protocol": {"type": "string"},
> + "eport": {"type": {"key": "integer"}}, "lport": {"type":
> {"key": "integer"}}},
> "isRoot": false},
> "DHCP_Options": {
> "columns": {
> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
> index c5ebbea..ec80ced 100644
> --- a/ovn/ovn-nb.xml
> +++ b/ovn/ovn-nb.xml
> @@ -1276,6 +1276,14 @@
> An IPv4 address.
> </column>
>
> + <column name="eport">
> + port responding to external_ip.
> + </column>
> +
> + <column name="lport">
> + port responding to logical_ip.
> + </column>
> +
> <column name="external_mac">
> <p>
> A MAC address.
> @@ -1317,6 +1325,16 @@
> port instance on the <code>redirect-chassis</code>.
> </p>
> </column>
> +
> + <column name="protocol">
> + <p>
> + Valid protocols are <code>tcp</code> or <code>udp</code> or
> <code>all</code>.
> + This column is useful when a port number is provided as part of
> the
> + <code>vips</code> column. If this column is empty and a port
> number
> + is provided as part of <code>vips</code> column, OVN assumes the
> + protocol to be <code>tcp</code>.
> + </p>
> + </column>
> </table>
>
> <table name="DHCP_Options" title="DHCP options">
> diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c
> index 3dac434..4e376dd 100644
> --- a/ovn/utilities/ovn-nbctl.c
> +++ b/ovn/utilities/ovn-nbctl.c
> @@ -2208,7 +2208,8 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
> const char *nat_type = ctx->argv[2];
> const char *external_ip = ctx->argv[3];
> const char *logical_ip = ctx->argv[4];
> - char *new_logical_ip = NULL;
> + ovs_be16 lport = 0, eport = 0;
> + char *new_logical_ip = NULL, *prt = NULL;
>
> lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true);
>
> @@ -2229,6 +2230,15 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
> ctl_fatal("%s: should be an IPv4 address.", logical_ip);
> }
> new_logical_ip = xstrdup(logical_ip);
> +
> + if (!strcmp("dnat", nat_type) && ctx->argc > 6) {
> + prt = ctx->argv[5];
> + eport = (ovs_be16)atoi(ctx->argv[6]);
> +
> + lport = ctx->argc == 8 ? (ovs_be16)atoi(ctx->argv[7]) : eport;
> + } else {
> + ctl_fatal("lr-nat-add with eport and lport");
> + }
> } else {
> char *error = ip_parse_cidr(logical_ip, &ipv4, &plen);
> if (error) {
> @@ -2241,10 +2251,10 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
>
> const char *logical_port;
> const char *external_mac;
> - if (ctx->argc == 6) {
> + if (ctx->argc == 6 && strcmp(nat_type, "dnat") || ctx->argc == 9 &&
> !strcmp(nat_type, "dnat")) {
> ctl_fatal("lr-nat-add with logical_port "
> "must also specify external_mac.");
> - } else if (ctx->argc == 7) {
> + } else if (ctx->argc == 7 && strcmp(nat_type, "dnat")) {
> if (strcmp(nat_type, "dnat_and_snat")) {
> ctl_fatal("logical_port and external_mac are only valid when "
> "type is \"dnat_and_snat\".");
> @@ -2258,6 +2268,9 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
> if (!eth_addr_from_string(external_mac, &ea)) {
> ctl_fatal("invalid mac address %s.", external_mac);
> }
> + } else if (ctx->argc == 10 && !strcmp(nat_type, "dnat")) {
> + ctl_fatal("logical_port and external_mac are only valid when "
> + "type is \"dnat_and_snat\".");
> } else {
> logical_port = NULL;
> external_mac = NULL;
> @@ -2272,18 +2285,24 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
> is_snat ? nat->logical_ip : nat->external_ip)) {
> if (!strcmp(is_snat ? external_ip : new_logical_ip,
> is_snat ? nat->external_ip :
> nat->logical_ip)) {
> - if (may_exist) {
> - nbrec_nat_verify_logical_port(nat);
> - nbrec_nat_verify_external_mac(nat);
> - nbrec_nat_set_logical_port(nat,
> logical_port);
> - nbrec_nat_set_external_mac(nat,
> external_mac);
> - free(new_logical_ip);
> - return;
> - }
> - ctl_fatal("%s, %s: a NAT with this external_ip
> and "
> + if ( !strcmp(nat_type, "dnat") && (eport != nat->eport
> || strcmp(prt, nat->protocol))) {
> + continue;
> + }
> + if (may_exist) {
> + nbrec_nat_verify_logical_port(nat);
> + nbrec_nat_verify_external_mac(nat);
> + nbrec_nat_set_logical_port(nat, logical_port);
> + nbrec_nat_set_external_mac(nat, external_mac);
> + free(new_logical_ip);
> + return;
> + }
> + ctl_fatal("%s:%d, %s:%d a NAT with this external_ip
> and "
> "logical_ip already exists",
> - external_ip, new_logical_ip);
> - } else {
> + external_ip, (ovs_be16)eport,
> new_logical_ip, (ovs_be16)lport);
> + } else if (!strcmp("dnat", nat_type)){
> + if (eport == nat->eport && !strcmp(prt,
> nat->protocol))
> + ctl_fatal("A DNAT can not mapped to multiple
> logical ip");
> + } else {
> ctl_fatal("a NAT with this type (%s) and %s (%s) "
> "already exists",
> nat_type,
> @@ -2299,6 +2318,11 @@ nbctl_lr_nat_add(struct ctl_context *ctx)
> nbrec_nat_set_type(nat, nat_type);
> nbrec_nat_set_external_ip(nat, external_ip);
> nbrec_nat_set_logical_ip(nat, new_logical_ip);
> + if (!strcmp(nat_type, "dnat")) {
> + nbrec_nat_set_lport(nat, lport);
> + nbrec_nat_set_eport(nat, eport);
> + nbrec_nat_set_protocol(nat, prt);
> + }
> if (logical_port && external_mac) {
> nbrec_nat_set_logical_port(nat, logical_port);
> nbrec_nat_set_external_mac(nat, external_mac);
> @@ -2353,12 +2377,25 @@ nbctl_lr_nat_del(struct ctl_context *ctx)
> }
>
> const char *nat_ip = ctx->argv[3];
> + const char *pt = NULL;
> + ovs_be16 port = 0;
> + if(!strcmp(nat_type, "dnat")) {
> + if (ctx->argc == 6){
> + port = (ovs_be16)atoi(ctx->argv[5]);
> + pt = ctx->argv[4];
> + }
> + }
> int is_snat = !strcmp("snat", nat_type);
> /* Remove the matching NAT. */
> for (size_t i = 0; i < lr->n_nat; i++) {
> struct nbrec_nat *nat = lr->nat[i];
> if (!strcmp(nat_type, nat->type) &&
> !strcmp(nat_ip, is_snat ? nat->logical_ip :
> nat->external_ip)) {
> + if (!strcmp("dnat", nat_type) && pt && (port != nat->eport ||
> strcmp(pt, nat->protocol))) {
> + continue;
> + } else if (!pt && (nat->eport != 0 || nat->lport != 0)){
> + continue;
> + }
> struct nbrec_nat **new_nats
> = xmemdup(lr->nat, sizeof *new_nats * lr->n_nat);
> new_nats[i] = lr->nat[lr->n_nat - 1];
> @@ -2385,24 +2422,24 @@ nbctl_lr_nat_list(struct ctl_context *ctx)
> struct smap lr_nats = SMAP_INITIALIZER(&lr_nats);
> for (size_t i = 0; i < lr->n_nat; i++) {
> const struct nbrec_nat *nat = lr->nat[i];
> - const char *key = xasprintf("%-17.13s%s", nat->type,
> nat->external_ip);
> + const char *key = xasprintf("%-17.13s%-10.10s%-20.17s%-10d",
> nat->type, nat->protocol, nat->external_ip, (int)nat->eport & 0xffff);
> if (nat->external_mac && nat->logical_port) {
> - smap_add_format(&lr_nats, key, "%-22.18s%-21.17s%s",
> - nat->logical_ip, nat->external_mac,
> + smap_add_format(&lr_nats, key, "%-20.17s%-10d%-22.17s%s",
> + nat->logical_ip, (int)nat->lport & 0xffff,
> nat->external_mac,
> nat->logical_port);
> } else {
> - smap_add_format(&lr_nats, key, "%s", nat->logical_ip);
> + smap_add_format(&lr_nats, key, "%-20.17s%-10d",
> nat->logical_ip, (int)nat->lport & 0xffff);
> }
> }
>
> const struct smap_node **nodes = smap_sort(&lr_nats);
> if (nodes) {
> - ds_put_format(&ctx->output, "%-17.13s%-19.15s%-22.18s%-21.
> 17s%s\n",
> - "TYPE", "EXTERNAL_IP", "LOGICAL_IP", "EXTERNAL_MAC",
> + ds_put_format(&ctx->output, "%-17.13s%-10.10s%-20.17s%-
> 10s%-20.17s%-10s%-22.17s%s\n",
> + "TYPE", "PROTOCOL", "EXTERNAL_IP", "EPORT", "LOGICAL_IP",
> "LPORT", "EXTERNAL_MAC",
> "LOGICAL_PORT");
> for (size_t i = 0; i < smap_count(&lr_nats); i++) {
> const struct smap_node *node = nodes[i];
> - ds_put_format(&ctx->output, "%-36.32s%s\n",
> + ds_put_format(&ctx->output, "%-47.57s%s\n",
> node->key, node->value);
> }
> free(nodes);
> @@ -3353,10 +3390,10 @@ static const struct ctl_command_syntax
> nbctl_commands[] = {
> "", RO },
>
> /* NAT commands. */
> - { "lr-nat-add", 4, 6,
> + { "lr-nat-add", 4, 8,
> "ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]",
> NULL,
> nbctl_lr_nat_add, NULL, "--may-exist", RW },
> - { "lr-nat-del", 1, 3, "ROUTER [TYPE [IP]]", NULL,
> + { "lr-nat-del", 1, 6, "ROUTER [TYPE [IP] [PROTOCOL] [PORT]]", NULL,
> nbctl_lr_nat_del, NULL, "--if-exists", RW },
> { "lr-nat-list", 1, 1, "ROUTER", NULL, nbctl_lr_nat_list, NULL, "",
> RO },
>
> --
> 1.8.3.1
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
More information about the dev
mailing list