[ovs-dev] [PATCH v12 6/6] ovn: specify options:nat-addresses as "router"
Guru Shetty
guru at ovn.org
Fri Jan 27 18:20:49 UTC 2017
On 26 January 2017 at 01:20, Mickey Spiegel <mickeys.dev at gmail.com> wrote:
> Currently in OVN, the "nat-addresses" in the "options" column of a
> logical switch port of type "router" must be specified manually.
> Typically the user would specify as "nat-addresses" all of the NAT
> external IP addresses and load balancer IP addresses that have
> already been specified separately on the router.
>
> This patch allows the logical switch port's "nat-addresses" to be
> specified as the string "router". When ovn-northd sees this string,
> it automatically copies the following into the southbound
> Port_Binding's "nat-addresses" in the "options" column:
> The options:router-port's MAC address.
> Each NAT external IP address (of any NAT type) specified on the
> logical router of options:router-port.
> Each load balancer IP address specified on the logical router of
> options:router-port.
> This will cause the controller where the gateway router resides to
> issue gratuitous ARPs for each NAT external IP address and for each
> load balancer IP address specified on the gateway router.
>
> This patch is written as if it will be included in OVS 2.7. If it
> is deferred to OVS 2.8, then the OVS version mentioned in ovn-nb.xml
> will need to be updated from OVS 2.7 to OVS 2.8.
>
> Signed-off-by: Mickey Spiegel <mickeys.dev at gmail.com>
> ---
> ovn/northd/ovn-northd.c | 114 ++++++++++++++++++++++++++++++
> ++++++++----------
> ovn/ovn-nb.xml | 42 +++++++++++++++---
> tests/ovn.at | 60 +++++++++++++++++++++++++
> 3 files changed, 185 insertions(+), 31 deletions(-)
>
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index e24ff8f..efb8a74 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -1436,6 +1436,86 @@ join_logical_ports(struct northd_context *ctx,
> }
>
> static void
> +ip_address_and_port_from_lb_key(const char *key, char **ip_address,
> + uint16_t *port);
> +
> +static void
> +get_router_load_balancer_ips(const struct ovn_datapath *od,
> + struct sset *all_ips)
> +{
> + if (!od->nbr) {
> + return;
> + }
> +
> + for (int i = 0; i < od->nbr->n_load_balancer; i++) {
> + struct nbrec_load_balancer *lb = od->nbr->load_balancer[i];
> + struct smap *vips = &lb->vips;
> + struct smap_node *node;
> +
> + SMAP_FOR_EACH (node, vips) {
> + /* node->key contains IP:port or just IP. */
> + char *ip_address = NULL;
> + uint16_t port;
> +
> + ip_address_and_port_from_lb_key(node->key, &ip_address,
> &port);
> + if (!ip_address) {
> + continue;
> + }
> +
> + if (!sset_contains(all_ips, ip_address)) {
> + sset_add(all_ips, ip_address);
> + }
> +
> + free(ip_address);
> + }
> + }
> +}
> +
> +/* Returns a string consisting of the port's MAC address followed by the
> + * external IP addresses of all NAT rules defined on that router and the
> + * VIPs of all load balancers defined on that router. */
>
A comment that the called has to free the returned string is useful.
Also, the load balancer IP address can also be the IP address of the router
itself. For e.g: when it is ROUTER_IP:port. I guess, that is not a problem
when a GARP is sent for the router IP too.
Acked-by: Gurucharan Shetty <guru at ovn.org>
> +static char *
> +get_nat_addresses(const struct ovn_port *op)
> +{
> + struct eth_addr mac;
> + if (!op->nbrp || !op->od || !op->od->nbr
> + || (!op->od->nbr->n_nat && !op->od->nbr->n_load_balancer)
> + || !eth_addr_from_string(op->nbrp->mac, &mac)) {
> + return NULL;
> + }
> +
> + struct ds addresses = DS_EMPTY_INITIALIZER;
> + ds_put_format(&addresses, ETH_ADDR_FMT, ETH_ADDR_ARGS(mac));
> +
> + /* Get NAT IP addresses. */
> + for (int i = 0; i < op->od->nbr->n_nat; i++) {
> + const struct nbrec_nat *nat;
> + nat = op->od->nbr->nat[i];
> +
> + ovs_be32 ip, mask;
> +
> + char *error = ip_parse_masked(nat->external_ip, &ip, &mask);
> + if (error || mask != OVS_BE32_MAX) {
> + free(error);
> + continue;
> + }
> + ds_put_format(&addresses, " %s", nat->external_ip);
> + }
> +
> + /* A set to hold all load-balancer vips. */
> + struct sset all_ips = SSET_INITIALIZER(&all_ips);
> + get_router_load_balancer_ips(op->od, &all_ips);
> +
> + const char *ip_address;
> + SSET_FOR_EACH(ip_address, &all_ips) {
> + ds_put_format(&addresses, " %s", ip_address);
> + }
> + sset_destroy(&all_ips);
> +
> + return ds_steal_cstr(&addresses);
> +}
> +
> +static void
> ovn_port_update_sbrec(const struct ovn_port *op,
> struct hmap *chassis_qdisc_queues)
> {
> @@ -1524,7 +1604,15 @@ ovn_port_update_sbrec(const struct ovn_port *op,
>
> const char *nat_addresses = smap_get(&op->nbsp->options,
> "nat-addresses");
> - if (nat_addresses) {
> + if (nat_addresses && !strcmp(nat_addresses, "router")) {
> + if (op->peer && op->peer->nbrp) {
> + char *nats = get_nat_addresses(op->peer);
> + if (nats) {
> + smap_add(&new, "nat-addresses", nats);
> + free(nats);
> + }
> + }
> + } else if (nat_addresses) {
> struct lport_addresses laddrs;
> if (!extract_lsp_addresses(nat_addresses, &laddrs)) {
> static struct vlog_rate_limit rl =
> @@ -3869,29 +3957,7 @@ build_lrouter_flows(struct hmap *datapaths, struct
> hmap *ports,
>
> /* A set to hold all load-balancer vips that need ARP responses.
> */
> struct sset all_ips = SSET_INITIALIZER(&all_ips);
> -
> - for (int i = 0; i < op->od->nbr->n_load_balancer; i++) {
> - struct nbrec_load_balancer *lb =
> op->od->nbr->load_balancer[i];
> - struct smap *vips = &lb->vips;
> - struct smap_node *node;
> -
> - SMAP_FOR_EACH (node, vips) {
> - /* node->key contains IP:port or just IP. */
> - char *ip_address = NULL;
> - uint16_t port;
> -
> - ip_address_and_port_from_lb_key(node->key, &ip_address,
> &port);
> - if (!ip_address) {
> - continue;
> - }
> -
> - if (!sset_contains(&all_ips, ip_address)) {
> - sset_add(&all_ips, ip_address);
> - }
> -
> - free(ip_address);
> - }
> - }
> + get_router_load_balancer_ips(op->od, &all_ips);
>
> const char *ip_address;
> SSET_FOR_EACH(ip_address, &all_ips) {
> diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml
> index 2af46b6..57fbc98 100644
> --- a/ovn/ovn-nb.xml
> +++ b/ovn/ovn-nb.xml
> @@ -242,13 +242,41 @@
> </column>
>
> <column name="options" key="nat-addresses">
> - MAC address of the <code>router-port</code> followed by a list
> of
> - SNAT and DNAT IP addresses. This is used to send gratuitous
> ARPs for
> - SNAT and DNAT IP addresses via <code>localnet</code> and is
> valid for
> - only L3 gateway ports. Example: <code>80:fa:5b:06:72:b7
> 158.36.44.22
> - 158.36.44.24</code>. This would result in generation of
> gratuitous
> - ARPs for IP addresses 158.36.44.22 and 158.36.44.24 with a MAC
> - address of 80:fa:5b:06:72:b7.
> + <p>
> + This is used to send gratuitous ARPs for SNAT and DNAT IP
> + addresses via <code>localnet</code> and is valid for only L3
> + gateway ports.
> + </p>
> +
> + <p>
> + This must take one of the following forms:
> + </p>
> +
> + <dl>
> + <dt><code>router</code></dt>
> + <dd>
> + <p>
> + Gratuitous ARPs will be sent for all SNAT and DNAT
> external IP
> + addresses and for all load balancer IP addresses defined
> on the
> + <ref column="options" key="router-port"/>'s logical
> router,
> + using the <ref column="options" key="router-port"/>'s MAC
> + address.
> + </p>
> +
> + <p>
> + Supported only in OVN 2.7 and later. Earlier versions
> required
> + NAT addresses to be manually synchronized.
> + </p>
> + </dd>
> +
> + <dt><code>Ethernet address followed by one or more IPv4
> addresses</code></dt>
> + <dd>
> + Example: <code>80:fa:5b:06:72:b7 158.36.44.22
> + 158.36.44.24</code>. This would result in generation of
> + gratuitous ARPs for IP addresses 158.36.44.22 and
> 158.36.44.24
> + with a MAC address of 80:fa:5b:06:72:b7.
> + </dd>
> + </dl>
> </column>
> </group>
>
> diff --git a/tests/ovn.at b/tests/ovn.at
> index 6eed020..febe00a 100644
> --- a/tests/ovn.at
> +++ b/tests/ovn.at
> @@ -5219,6 +5219,66 @@ OVN_CLEANUP([hv1])
>
> AT_CLEANUP
>
> +AT_SETUP([ovn -- send gratuitous arp with nat-addresses router in
> localnet])
> +AT_SKIP_IF([test $HAVE_PYTHON = no])
> +ovn_start
> +# Create logical switch
> +ovn-nbctl ls-add ls0
> +# Create gateway router
> +ovn-nbctl create Logical_Router name=lr0 options:chassis=hv1
> +# Add router port to gateway router
> +ovn-nbctl lrp-add lr0 lrp0 f0:00:00:00:00:01 192.168.0.1/24
> +ovn-nbctl lsp-add ls0 lrp0-rp -- set Logical_Switch_Port lrp0-rp \
> + type=router options:router-port=lrp0-rp addresses='"f0:00:00:00:00:01"
> '
> +# Add nat-address option
> +ovn-nbctl lsp-set-options lrp0-rp router-port=lrp0 nat-addresses="router"
> +# Add NAT rules
> +AT_CHECK([ovn-nbctl lr-nat-add lr0 snat 192.168.0.1 10.0.0.0/24])
> +AT_CHECK([ovn-nbctl lr-nat-add lr0 dnat 192.168.0.2 10.0.0.1])
> +# Add load balancers
> +AT_CHECK([ovn-nbctl lb-add lb0 192.168.0.3:80 10.0.0.2:80,10.0.0.3:80])
> +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb0])
> +AT_CHECK([ovn-nbctl lb-add lb1 192.168.0.3:8080 10.0.0.2:8080,
> 10.0.0.3:8080])
> +AT_CHECK([ovn-nbctl lr-lb-add lr0 lb1])
> +
> +net_add n1
> +sim_add hv1
> +as hv1
> +ovs-vsctl \
> + -- add-br br-phys \
> + -- add-br br-eth0
> +
> +ovn_attach n1 br-phys 192.168.0.1
> +
> +AT_CHECK([ovs-vsctl set Open_vSwitch . external-ids:ovn-bridge-
> mappings=physnet1:br-eth0])
> +AT_CHECK([ovs-vsctl add-port br-eth0 snoopvif -- set Interface snoopvif
> options:tx_pcap=hv1/snoopvif-tx.pcap options:rxq_pcap=hv1/snoopvif-
> rx.pcap])
> +
> +# Create a localnet port.
> +AT_CHECK([ovn-nbctl lsp-add ls0 ln_port])
> +AT_CHECK([ovn-nbctl lsp-set-addresses ln_port unknown])
> +AT_CHECK([ovn-nbctl lsp-set-type ln_port localnet])
> +AT_CHECK([ovn-nbctl lsp-set-options ln_port network_name=physnet1])
> +
> +
> +# Wait for packet to be received.
> +OVS_WAIT_UNTIL([test `wc -c < "hv1/snoopvif-tx.pcap"` -ge 50])
> +trim_zeros() {
> + sed 's/\(00\)\{1,\}$//'
> +}
> +$PYTHON "$top_srcdir/utilities/ovs-pcap.in" hv1/snoopvif-tx.pcap |
> trim_zeros > packets
> +expected="fffffffffffff0000000000108060001080006040001f00000000001c0a8
> 0001000000000000c0a80001"
> +echo $expected > expout
> +expected="fffffffffffff0000000000108060001080006040001f00000000001c0a8
> 0002000000000000c0a80002"
> +echo $expected >> expout
> +expected="fffffffffffff0000000000108060001080006040001f00000000001c0a8
> 0003000000000000c0a80003"
> +echo $expected >> expout
> +AT_CHECK([sort packets], [0], [expout])
> +cat packets
> +
> +OVN_CLEANUP([hv1])
> +
> +AT_CLEANUP
> +
> AT_SETUP([ovn -- delete mac bindings])
> ovn_start
> net_add n1
> --
> 1.9.1
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
More information about the dev
mailing list