On 28 February 2017 at 19:16, lg.yue <[email protected]> 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" <[email protected]> > Date: Wed, 1 Mar 2017 11:07:16 +0800 > Subject: [PATCH 1/1] Implement DNAT based on destnation port > > Signed-off-by: lg.yue <[email protected]> > --- > 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 > [email protected] > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
