From d8573c28c74a4e706d1b16dc84ac28a74fe624f0 Mon Sep 17 00:00:00 2001 From: Ankur Sharma Date: Fri, 1 Nov 2019 01:27:36 +0000 Subject: [PATCH 06/12] OVN: ADD nbctl cli to mark a dnat_and_snat rule as stateless Adding ovn-nbctl to mark a dnat_and_snat rule as stateless. This configuration will be added to "options" column of NAT table. Signed-off-by: Ankur Sharma Signed-off-by: Numan Siddique --- ovn/ovn-nb.ovsschema | 6 ++++-- ovn/ovn-nb.xml | 5 +++++ ovn/utilities/ovn-nbctl.8.xml | 12 +++++++++++- ovn/utilities/ovn-nbctl.c | 30 +++++++++++++++++++++++++++- tests/ovn-nbctl.at | 37 +++++++++++++++++++++++++++++++++++ 5 files changed, 86 insertions(+), 4 deletions(-) diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 2c87cbba7..084305b24 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.16.0", - "cksum": "923459061 23095", + "version": "5.17.0", + "cksum": "1128988054 23237", "tables": { "NB_Global": { "columns": { @@ -345,6 +345,8 @@ "snat", "dnat_and_snat" ]]}}}, + "options": {"type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}, "external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index bce7463d2..cf2c5136a 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -2324,6 +2324,11 @@

+ + Indicates if a dnat_and_snat rule should lead to connection + tracking state or not. + + See External IDs at the beginning of this document. diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index 41d50b694..49aa527a0 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -665,7 +665,7 @@

NAT Commands

-
[--may-exist] lr-nat-add router type external_ip logical_ip [logical_port external_mac]
+
[--may-exist] [--stateless]lr-nat-add router type external_ip logical_ip [logical_port external_mac]

Adds the specified NAT to router. @@ -681,7 +681,17 @@ The logical_port is the name of an existing logical switch port where the logical_ip resides. The external_mac is an Ethernet address. + The --stateless

+

+ When --stateless is specified then it implies that + we will be not use connection tracker, i.e internal ip and external + ip are 1:1 mapped. This implies that --stateless is + applicable only to dnat_and_snat type NAT rules. + An external ip with --stateless NAT cannot be shared + with any other NAT rule. +

+

When type is dnat, the externally visible IP address external_ip is DNATted to the diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index 112cc1d54..1a1d83e65 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -685,6 +685,7 @@ Policy commands:\n\ lr-policy-list ROUTER print policies for ROUTER\n\ \n\ NAT commands:\n\ + [--stateless]\n\ lr-nat-add ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]\n\ add a NAT to ROUTER\n\ lr-nat-del ROUTER [TYPE [IP]]\n\ @@ -3945,6 +3946,13 @@ nbctl_lr_nat_add(struct ctl_context *ctx) } bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; + bool stateless = shash_find(&ctx->options, "--stateless") != NULL; + + if (strcmp(nat_type, "dnat_and_snat") && stateless) { + ctl_error(ctx, "stateless is not applicable to dnat or snat types"); + return; + } + int is_snat = !strcmp("snat", nat_type); for (size_t i = 0; i < lr->n_nat; i++) { const struct nbrec_nat *nat = lr->nat[i]; @@ -3976,10 +3984,25 @@ nbctl_lr_nat_add(struct ctl_context *ctx) return; } } + + } + if (!strcmp(nat_type, "dnat_and_snat") || + !strcmp(nat->type, "dnat_and_snat")) { + + if (!strcmp(nat->external_ip, external_ip)) { + struct smap nat_options = SMAP_INITIALIZER(&nat_options); + if (!strcmp(smap_get(&nat->options, "stateless"), + "true") || stateless) { + ctl_error(ctx, "%s, %s: External ip cannot be shared " + "across stateless and stateful NATs", + external_ip, new_logical_ip); + } + } } } /* Create the NAT. */ + struct smap nat_options = SMAP_INITIALIZER(&nat_options); struct nbrec_nat *nat = nbrec_nat_insert(ctx->txn); nbrec_nat_set_type(nat, nat_type); nbrec_nat_set_external_ip(nat, external_ip); @@ -3988,7 +4011,12 @@ nbctl_lr_nat_add(struct ctl_context *ctx) nbrec_nat_set_logical_port(nat, logical_port); nbrec_nat_set_external_mac(nat, external_mac); } + + smap_add(&nat_options, "stateless", stateless ? "true":"false"); + nbrec_nat_set_options(nat, &nat_options); + free(new_logical_ip); + smap_destroy(&nat_options); /* Insert the NAT into the logical router. */ nbrec_logical_router_verify_nat(lr); @@ -5707,7 +5735,7 @@ static const struct ctl_command_syntax nbctl_commands[] = { /* NAT commands. */ { "lr-nat-add", 4, 6, "ROUTER TYPE EXTERNAL_IP LOGICAL_IP [LOGICAL_PORT EXTERNAL_MAC]", NULL, - nbctl_lr_nat_add, NULL, "--may-exist", RW }, + nbctl_lr_nat_add, NULL, "--may-exist,--stateless", RW }, { "lr-nat-del", 1, 3, "ROUTER [TYPE [IP]]", NULL, nbctl_lr_nat_del, NULL, "--if-exists", RW }, { "lr-nat-list", 1, 1, "ROUTER", NULL, nbctl_lr_nat_list, NULL, "", RO }, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 620b778b7..d5dce90f4 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -533,6 +533,39 @@ snat 30.0.0.1 192.168.1.0/24 snat fd01::1 fd11::/64 ]) +AT_CHECK([ovn-nbctl --bare --columns=options list nat | grep stateless=true| wc -l], [0], +[0 +]) +AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat_and_snat 40.0.0.2 192.168.1.4]) +AT_CHECK([ovn-nbctl --bare --columns=options list nat | grep stateless=true| wc -l], [0], +[1 +]) + +AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat_and_snat fd21::1 fd11::2]) +AT_CHECK([ovn-nbctl --bare --columns=options list nat | grep stateless=true| wc -l], [0], +[2 +]) + +AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat fd21::1]) + +AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat 40.0.0.2 192.168.1.4], [1], [], +[ovn-nbctl: stateless is not applicable to dnat or snat types +]) +AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 snat 40.0.0.2 192.168.1.4], [1], [], +[ovn-nbctl: stateless is not applicable to dnat or snat types +]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 40.0.0.2 192.168.1.5], [1], [], +[ovn-nbctl: 40.0.0.2, 192.168.1.5: External ip cannot be shared across stateless and stateful NATs +]) +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 40.0.0.2 192.168.1.5], [1], [], +[ovn-nbctl: 40.0.0.2, 192.168.1.5: External ip cannot be shared across stateless and stateful NATs +]) + +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 40.0.0.3 192.168.1.6]) +AT_CHECK([ovn-nbctl --stateless lr-nat-add lr0 dnat_and_snat 40.0.0.3 192.168.1.7], [1], [], +[ovn-nbctl: 40.0.0.3, 192.168.1.7: External ip cannot be shared across stateless and stateful NATs +]) + dnl Deletes the NATs AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat_and_snat 30.0.0.3], [1], [], [ovn-nbctl: no matching NAT with the type (dnat_and_snat) and external_ip (30.0.0.3) @@ -552,8 +585,10 @@ TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC L dnat 30.0.0.1 192.168.1.2 dnat fd01::1 fd11::2 dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat 40.0.0.2 192.168.1.4 dnat_and_snat fd01::2 fd11::3 snat 30.0.0.1 192.168.1.0/24 +snat 40.0.0.3 192.168.1.6 snat fd01::1 fd11::/64 ]) @@ -561,8 +596,10 @@ AT_CHECK([ovn-nbctl lr-nat-del lr0 dnat]) AT_CHECK([ovn-nbctl lr-nat-list lr0], [0], [dnl TYPE EXTERNAL_IP LOGICAL_IP EXTERNAL_MAC LOGICAL_PORT dnat_and_snat 30.0.0.2 192.168.1.3 +dnat_and_snat 40.0.0.2 192.168.1.4 dnat_and_snat fd01::2 fd11::3 snat 30.0.0.1 192.168.1.0/24 +snat 40.0.0.3 192.168.1.6 snat fd01::1 fd11::/64 ]) -- 2.23.0