[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