Permalink
Browse files

ovn: Support address sets generated from port groups

Address sets are automatically generated from corresponding port
groups, and can be used directly in ACL match conditions.

There are two address sets generated for each port group:

<port group name>_ip4
<port group name>_ip6

For example, if port_group1 is created, we can directly use below
match condition in ACL:
    "outport == @port_group1 && ip4.src == $port_group1_ip4"

This will simplify OVN client implementation, and avoid some tricky
problems such as race conditions when maintaining address set
memberships as discussed in the link below.

Reported-by: Lucas Alvares Gomes <lucasagomes@gmail.com>
Reported-at: https://mail.openvswitch.org/pipermail/ovs-discuss/2018-February/046174.html
Reviewed-by: Mark Michelson <mmichels@redhat.com>
Reviewed-by: Daniel Alvarez <dalvarez@redhat.com>
Signed-off-by: Han Zhou <hzhou8@ebay.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
  • Loading branch information...
hzhou8 authored and blp committed Apr 14, 2018
1 parent 73ac791 commit 689829d53612a573f810271a01561f7b0948c8c8
Showing with 352 additions and 17 deletions.
  1. +2 −1 NEWS
  2. +85 −14 ovn/northd/ovn-northd.c
  3. +18 −0 ovn/ovn-nb.xml
  4. +21 −2 ovn/ovn-sb.xml
  5. +226 −0 tests/ovn.at
3 NEWS
@@ -20,7 +20,8 @@ Post-v2.9.0
* implemented icmp4/icmp6/tcp_reset actions in order to drop the packet
and reply with a RST for TCP or ICMPv4/ICMPv6 unreachable message for
other IPv4/IPv6-based protocols whenever a reject ACL rule is hit.
* ACL match conditions can now match on Port_Groups.
* ACL match conditions can now match on Port_Groups as well as address
sets that are automatically generated by Port_Groups.

v2.9.0 - 19 Feb 2018
--------------------
@@ -6179,9 +6179,32 @@ build_lflows(struct northd_context *ctx, struct hmap *datapaths,
hmap_destroy(&mcgroups);
}

/* OVN_Northbound and OVN_Southbound have an identical Address_Set table.
* We always update OVN_Southbound to match the current data in
* OVN_Northbound, so that the address sets used in Logical_Flows in
static void
sync_address_set(struct northd_context *ctx, const char *name,
const char **addrs, size_t n_addrs,
struct shash *sb_address_sets)
{
const struct sbrec_address_set *sb_address_set;
sb_address_set = shash_find_and_delete(sb_address_sets,
name);
if (!sb_address_set) {
sb_address_set = sbrec_address_set_insert(ctx->ovnsb_txn);
sbrec_address_set_set_name(sb_address_set, name);
}

sbrec_address_set_set_addresses(sb_address_set,
addrs, n_addrs);
}

/* OVN_Southbound Address_Set table contains same records as in north
* bound, plus the records generated from Port_Group table in north bound.
*
* There are 2 records generated from each port group, one for IPv4, and
* one for IPv6, named in the format: <port group name>_ip4 and
* <port group name>_ip6 respectively. MAC addresses are ignored.
*
* We always update OVN_Southbound to match the Address_Set and Port_Group
* in OVN_Northbound, so that the address sets used in Logical_Flows in
* OVN_Southbound is checked against the proper set.*/
static void
sync_address_sets(struct northd_context *ctx)
@@ -6193,19 +6216,67 @@ sync_address_sets(struct northd_context *ctx)
shash_add(&sb_address_sets, sb_address_set->name, sb_address_set);
}

const struct nbrec_address_set *nb_address_set;
NBREC_ADDRESS_SET_FOR_EACH (nb_address_set, ctx->ovnnb_idl) {
sb_address_set = shash_find_and_delete(&sb_address_sets,
nb_address_set->name);
if (!sb_address_set) {
sb_address_set = sbrec_address_set_insert(ctx->ovnsb_txn);
sbrec_address_set_set_name(sb_address_set, nb_address_set->name);
/* sync port group generated address sets first */
const struct nbrec_port_group *nb_port_group;
NBREC_PORT_GROUP_FOR_EACH (nb_port_group, ctx->ovnnb_idl) {
char **ipv4_addrs = xcalloc(1, sizeof *ipv4_addrs);
size_t n_ipv4_addrs = 0;
size_t n_ipv4_addrs_buf = 1;
char **ipv6_addrs = xcalloc(1, sizeof *ipv6_addrs);
size_t n_ipv6_addrs = 0;
size_t n_ipv6_addrs_buf = 1;
for (size_t i = 0; i < nb_port_group->n_ports; i++) {
for (size_t j = 0; j < nb_port_group->ports[i]->n_addresses; j++) {
struct lport_addresses laddrs;
extract_lsp_addresses(nb_port_group->ports[i]->addresses[j],
&laddrs);
while (n_ipv4_addrs_buf < n_ipv4_addrs + laddrs.n_ipv4_addrs) {
n_ipv4_addrs_buf *= 2;
ipv4_addrs = xrealloc(ipv4_addrs,
n_ipv4_addrs_buf * sizeof *ipv4_addrs);
}
for (size_t k = 0; k < laddrs.n_ipv4_addrs; k++) {
ipv4_addrs[n_ipv4_addrs++] =
xstrdup(laddrs.ipv4_addrs[k].addr_s);
}
while (n_ipv6_addrs_buf < n_ipv6_addrs + laddrs.n_ipv6_addrs) {
n_ipv6_addrs_buf *= 2;
ipv6_addrs = xrealloc(ipv6_addrs,
n_ipv6_addrs_buf * sizeof *ipv6_addrs);
}
for (size_t k = 0; k < laddrs.n_ipv6_addrs; k++) {
ipv6_addrs[n_ipv6_addrs++] =
xstrdup(laddrs.ipv6_addrs[k].addr_s);
}
destroy_lport_addresses(&laddrs);
}
}
char *ipv4_addrs_name = xasprintf("%s_ip4", nb_port_group->name);
char *ipv6_addrs_name = xasprintf("%s_ip6", nb_port_group->name);
sync_address_set(ctx, ipv4_addrs_name, (const char **)ipv4_addrs,
n_ipv4_addrs, &sb_address_sets);
sync_address_set(ctx, ipv6_addrs_name, (const char **)ipv6_addrs,
n_ipv6_addrs, &sb_address_sets);
free(ipv4_addrs_name);
free(ipv6_addrs_name);
for (size_t i = 0; i < n_ipv4_addrs; i++) {
free(ipv4_addrs[i]);
}
free(ipv4_addrs);
for (size_t i = 0; i < n_ipv6_addrs; i++) {
free(ipv6_addrs[i]);
}
free(ipv6_addrs);
}

sbrec_address_set_set_addresses(sb_address_set,
/* "char **" is not compatible with "const char **" */
(const char **) nb_address_set->addresses,
nb_address_set->n_addresses);
/* sync user defined address sets, which may overwrite port group
* generated address sets if same name is used */
const struct nbrec_address_set *nb_address_set;
NBREC_ADDRESS_SET_FOR_EACH (nb_address_set, ctx->ovnnb_idl) {
sync_address_set(ctx, nb_address_set->name,
/* "char **" is not compatible with "const char **" */
(const char **)nb_address_set->addresses,
nb_address_set->n_addresses, &sb_address_sets);
}

struct shash_node *node, *next;
@@ -936,6 +936,24 @@
db="OVN_Southbound"/> database.
</p>

<p>
For each port group, there are two address sets generated to the
<ref table="Address_Set" db="OVN_Southbound"/> table of the
<ref db="OVN_Southbound"/> database, containing the IP addresses
of the group of ports, one for IPv4, and the other for IPv6, with
<ref column="name" table="Address_Set" db="OVN_Southbound"/> being
the <ref column="name" table="Port_Group" db="OVN_Northbound"/>
of the <ref table="Port_Group" db="OVN_Northbound"/> followed by
a suffix <code>_ip4</code> for IPv4 and <code>_ip6</code> for IPv6.
The generated address sets can be used in the same way as regular
address sets in the <ref column="match" table="ACL"/> column
of the <ref table="ACL"/> table. For syntax information, see the details
of the expression language used for the <ref column="match"
table="Logical_Flow" db="OVN_Southbound"/> column in the <ref
table="Logical_Flow" db="OVN_Southbound"/> table of the <ref
db="OVN_Southbound"/> database.
</p>

<column name="name">
A name for the port group. Names are ASCII and must match
<code>[a-zA-Z_.][a-zA-Z_.0-9]*</code>.
@@ -368,9 +368,17 @@

<table name="Address_Set" title="Address Sets">
<p>
See the documentation for the <ref table="Address_Set"
This table contains address sets synced from the <ref table="Address_Set"
db="OVN_Northbound"/> table in the <ref db="OVN_Northbound"/> database
for details.
and address sets generated from the <ref table="Port_Group"
db="OVN_Northbound"/> table in the <ref db="OVN_Northbound"/> database.
</p>

<p>
See the documentation for the <ref table="Address_Set"
db="OVN_Northbound"/> table and <ref table="Port_Group"
db="OVN_Northbound"/> table in the <ref db="OVN_Northbound"/>
database for details.
</p>

<column name="name"/>
@@ -790,6 +798,17 @@
<code>@port_group1</code>.
</p>

<p>
Additionally, you may refer to the set of addresses belonging to a
group of logical switch ports stored in the <ref table="Port_Group"/>
table by its <ref column="name" table="Port_Group"/> followed by
a suffix '_ip4'/'_ip6'. The IPv4 address set of a
<ref table="Port_Group"/> with a name of <code>port_group1</code>
can be referred to as <code>$port_group1_ip4</code>, and the IPv6
address set of the same <ref table="Port_Group"/> can be referred to
as <code>$port_group1_ip6</code>
</p>

<p><em>Miscellaneous</em></p>

<p>
Oops, something went wrong.

0 comments on commit 689829d

Please sign in to comment.