Skip to content

Commit

Permalink
ovn-northd-ddlog: Add IGMP Snooping & Relay
Browse files Browse the repository at this point in the history
Signed-off-by: Dumitru Ceara <dceara@redhat.com>
  • Loading branch information
dceara committed Sep 23, 2019
1 parent 60bc377 commit 759cefc
Show file tree
Hide file tree
Showing 8 changed files with 771 additions and 54 deletions.
7 changes: 6 additions & 1 deletion northd/automake.mk
Expand Up @@ -13,7 +13,7 @@ EXTRA_DIST += \
northd/ovn-northd northd/ovn-northd.8.xml \
northd/ovn_northd.dl northd/ovn.dl northd/ovn.rs \
northd/ovn.toml northd/lswitch.dl northd/lrouter.dl \
northd/helpers.dl northd/ipam.dl \
northd/helpers.dl northd/ipam.dl northd/multicast.dl \
northd/docs/design.md northd/docs/debugging.md

if DDLOG
Expand Down Expand Up @@ -58,10 +58,13 @@ northd/OVN_Southbound.dl: ovn-sb.ovsschema
-o DNS \
-o RBAC_Role \
-o RBAC_Permission \
-o IP_Multicast \
-p Datapath_Binding \
-p Port_Binding \
-p Multicast_Group \
--ro Port_Binding.chassis \
--ro Port_Binding.encap \
--ro IP_Multicast.seq_no \
--ro SB_Global.ssl \
--ro SB_Global.connections \
--ro SB_Global.external_ids \
Expand All @@ -81,6 +84,7 @@ northd/OVN_Southbound.dl: ovn-sb.ovsschema
-k Logical_Flow.priority \
-k Logical_Flow.match \
-k Logical_Flow.actions \
-k IP_Multicast.datapath \
> $@

CLEANFILES += northd/OVN_Northbound.dl northd/OVN_Southbound.dl
Expand All @@ -96,6 +100,7 @@ northd/ovn_northd_ddlog/target/release/libovn_northd_ddlog.a: \
northd/lswitch.dl \
northd/lrouter.dl \
northd/ipam.dl \
northd/multicast.dl \
northd/ovn.dl \
northd/ovn.rs \
northd/helpers.dl \
Expand Down
44 changes: 44 additions & 0 deletions northd/helpers.dl
Expand Up @@ -28,3 +28,47 @@ SwitchRouterPeer(lsp, lsp_name, lrp) :-
nb.Logical_Switch_Port(._uuid = lsp, .name = lsp_name, .__type = "router", .options = options),
Some{var router_port} = map_get(options, "router-port"),
nb.Logical_Router_Port(.name = router_port, ._uuid = lrp).

function map_get_bool_def(m: Map<string, string>,
k: string, def: bool): bool = {
match (map_get(m, k)) {
None -> def,
Some{x} -> {
if (def) {
str_to_lower(x) != "false"
} else {
str_to_lower(x) == "true"
}
}
}
}

function map_get_int_def(m: Map<string, string>, k: string,
def: integer): integer = {
match (map_get(m, k)) {
None -> def,
Some{x} -> {
match (str_to_int(x, 10)) {
Some{v} -> v,
None -> def
}
}
}
}

function map_get_int_def_limit(m: Map<string, string>, k: string, def: integer,
min: integer, max: integer): integer = {
var v = map_get_int_def(m, k, def);
var v1 = {
if (v < min) min else v
};
if (v1 > max) max else v1
}

function map_get_str_def(m: Map<string, string>, k: string,
def: string): string = {
match (map_get(m, k)) {
None -> def,
Some{x} -> x
}
}
12 changes: 8 additions & 4 deletions northd/lrouter.dl
@@ -1,4 +1,5 @@
import OVN_Northbound as nb
import multicast
import ovsdb
import ovn
import helpers
Expand Down Expand Up @@ -125,7 +126,8 @@ relation &Router(
redirect_port_name: string,
is_gateway: bool,
nats: Vec<Ref<nb.NAT>>,
lbs: Vec<Ref<nb.Load_Balancer>>
lbs: Vec<Ref<nb.Load_Balancer>>,
mcast_cfg: Ref<McastRouterCfg>
)

&Router(.lr = lr,
Expand All @@ -137,12 +139,14 @@ relation &Router(
_ -> ""
},
.is_gateway = is_some(map_get(lr.options, "chassis")),
.nats = nats,
.lbs = lbs) :-
.nats = nats,
.lbs = lbs,
.mcast_cfg = mcast_cfg) :-
nb.Logical_Router[lr],
LogicalRouterRedirectPort(lr._uuid, l3dgw_port),
LogicalRouterNATs(lr._uuid, nats),
LogicalRouterLBs(lr._uuid, lbs).
LogicalRouterLBs(lr._uuid, lbs),
mcast_cfg in &McastRouterCfg(.datapath = lr._uuid).

/* RouterLB: many-to-many relation between logical routers and nb.LB */
relation RouterLB(router: Ref<Router>, lb: Ref<nb.Load_Balancer>)
Expand Down
8 changes: 6 additions & 2 deletions northd/lswitch.dl
Expand Up @@ -3,6 +3,7 @@ import OVN_Southbound as sb
import ovsdb
import ovn
import lrouter
import multicast
import helpers
import ipam

Expand Down Expand Up @@ -130,7 +131,8 @@ relation &Switch(
has_dns_records: bool,
has_localnet_port: bool,
subnet: Option<(ovs_be32/*subnet*/, ovs_be32/*mask*/, bit<32>/*start_ipv4*/, bit<32>/*total_ipv4s*/)>,
ipv6_prefix: Option<in6_addr>
ipv6_prefix: Option<in6_addr>,
mcast_cfg: Ref<McastSwitchCfg>
)

&Switch(.ls = ls,
Expand All @@ -139,11 +141,13 @@ relation &Switch(
.has_dns_records = has_dns_records,
.has_localnet_port = has_localnet_port,
.subnet = subnet,
.ipv6_prefix = ipv6_prefix) :-
.ipv6_prefix = ipv6_prefix,
.mcast_cfg = mcast_cfg) :-
nb.Logical_Switch[ls],
LogicalSwitchHasStatefulACL(ls._uuid, has_stateful_acl),
LogicalSwitchHasDNSRecords(ls._uuid, has_dns_records),
LogicalSwitchHasLocalnetPort(ls._uuid, has_localnet_port),
mcast_cfg in &McastSwitchCfg(.datapath = ls._uuid),
var subnet: Option<(ovs_be32, ovs_be32, bit<32>, bit<32>)> =
match (map_get(ls.other_config, "subnet")) {
None -> None,
Expand Down
161 changes: 161 additions & 0 deletions northd/multicast.dl
@@ -0,0 +1,161 @@
import OVN_Northbound as nb
import OVN_Southbound as sb
import ovsdb
import helpers
import lswitch
import lrouter

function mCAST_DEFAULT_MAX_ENTRIES(): integer = 2048

function mCAST_DEFAULT_IDLE_TIMEOUT_S(): integer = 300
function mCAST_DEFAULT_MIN_IDLE_TIMEOUT_S(): integer = 15
function mCAST_DEFAULT_MAX_IDLE_TIMEOUT_S(): integer = 3600

function mCAST_DEFAULT_MIN_QUERY_INTERVAL_S(): integer = 1
function mCAST_DEFAULT_MAX_QUERY_INTERVAL_S(): integer =
mCAST_DEFAULT_MAX_IDLE_TIMEOUT_S()

function mCAST_DEFAULT_QUERY_MAX_RESPONSE_S(): integer = 1

/* IP Multicast per switch configuration. */
relation &McastSwitchCfg(
datapath : uuid,
enabled : bool,
querier : bool,
flood_unreg : bool,
eth_src : string,
ip4_src : string,
table_size : integer,
idle_timeout : integer,
query_interval: integer,
query_max_resp: integer
)

/* FIXME: Right now table_size is enforced only in ovn-controller but in
* the ovn-northd C version we enforce it on the aggregate groups too.
*/

&McastSwitchCfg(
.datapath = ls_uuid,
.enabled = map_get_bool_def(other_config, "mcast_snoop",
false),
.querier = map_get_bool_def(other_config, "mcast_querier",
true),
.flood_unreg = map_get_bool_def(other_config,
"mcast_flood_unregistered",
false),
.eth_src = map_get_str_def(other_config, "mcast_eth_src", ""),
.ip4_src = map_get_str_def(other_config, "mcast_ip4_src", ""),
.table_size = map_get_int_def(other_config,
"mcast_table_size",
mCAST_DEFAULT_MAX_ENTRIES()),
.idle_timeout = idle_timeout,
.query_interval = query_interval,
.query_max_resp = query_max_resp) :-
nb.Logical_Switch(._uuid = ls_uuid,
.other_config = other_config),
var idle_timeout =
map_get_int_def_limit(other_config, "mcast_idle_timeout",
mCAST_DEFAULT_IDLE_TIMEOUT_S(),
mCAST_DEFAULT_MIN_IDLE_TIMEOUT_S(),
mCAST_DEFAULT_MAX_IDLE_TIMEOUT_S()),
var query_interval =
map_get_int_def_limit(other_config, "mcast_query_interval",
idle_timeout / 2,
mCAST_DEFAULT_MIN_QUERY_INTERVAL_S(),
mCAST_DEFAULT_MAX_QUERY_INTERVAL_S()),
var query_max_resp =
map_get_int_def(other_config, "mcast_query_max_response",
mCAST_DEFAULT_QUERY_MAX_RESPONSE_S()).

/* IP Multicast per router configuration. */
relation &McastRouterCfg(
datapath: uuid,
relay : bool
)

&McastRouterCfg(lr_uuid, mcast_relay) :-
nb.Logical_Router(._uuid = lr_uuid, .options = options),
var mcast_relay = map_get_bool_def(options, "mcast_relay", false).

/* Mapping between Switch and the set of router port uuids on which to flood
* IP multicast for relay.
*/
relation SwitchMcastFloodRelayPorts(sw: Ref<Switch>, ports: Set<uuid>)

SwitchMcastFloodRelayPorts(switch, relay_ports) :-
&SwitchPort(
.lsp = lsp,
.sw = switch,
.peer = Some{&RouterPort{.router = &Router{.mcast_cfg = &mcast_cfg}}}
), mcast_cfg.relay,
var lsp_uuid = lsp._uuid,
var relay_ports = Aggregate((switch), group2set(lsp_uuid)).

SwitchMcastFloodRelayPorts(switch, set_empty()) :-
Switch[switch].

/* Relation used to determine if a Switch has at least one router port
* connected to a Router with multicast relay enabled.
*/
relation SwitchHasMcastFloodRelay(sw: Ref<Switch>, has_flood_relay: bool)

SwitchHasMcastFloodRelay(switch, not set_is_empty(ports)) :-
SwitchMcastFloodRelayPorts(switch, ports).

/* Flattened IGMP group. One record per address-port tuple. */
relation IgmpSwitchGroupPort(
address: string,
switch : Ref<Switch>,
port : uuid
)

IgmpSwitchGroupPort(address, switch, lsp._uuid) :-
sb.IGMP_Group(.address = address, .datapath = igmp_dp_set,
.ports = pb_ports),
var pb_port_uuid = FlatMap(pb_ports),
port in &SwitchPort(.lsp = lsp, .sw = switch),
sb.Port_Binding(._uuid = pb_port_uuid, .logical_port = lsp.name).

/* Aggregated IGMP group: merges all IgmpSwitchGroupPort for a given
* address-switch tuple from all chassis.
*/
relation IgmpSwitchMulticastGroup(
address: string,
switch : Ref<Switch>,
ports : Set<uuid>
)

IgmpSwitchMulticastGroup(address, switch, ports) :-
IgmpSwitchGroupPort(address, switch, port),
var ports = Aggregate((address, switch), group2set(port)).

/* Flattened IGMP group representation for routers with relay enabled. One
* record per address-port tuple for all IGMP groups learned by switches
* connected to the router.
*/
relation IgmpRouterGroupPort(
address: string,
router : Ref<Router>,
port : uuid
)

IgmpRouterGroupPort(address, rtr_port.router, rtr_port.lrp._uuid) :-
SwitchMcastFloodRelayPorts(switch, sw_flood_ports),
IgmpSwitchMulticastGroup(address, switch, _),
var flood_port = FlatMap(sw_flood_ports),
&SwitchPort(.lsp = lsp, .peer = Some{&rtr_port}),
lsp._uuid == flood_port.

/* Aggregated IGMP group for routers: merges all IgmpRouterGroupPort for
* a given address-router tuple from all connected switches.
*/
relation IgmpRouterMulticastGroup(
address: string,
router : Ref<Router>,
ports : Set<uuid>
)

IgmpRouterMulticastGroup(address, router, ports) :-
IgmpRouterGroupPort(address, router, port),
var ports = Aggregate((address, router), group2set(port)).
4 changes: 3 additions & 1 deletion northd/ovn-northd-ddlog.c
Expand Up @@ -95,7 +95,8 @@ static const char *sb_input_relations[] = {
"DNS",
"RBAC_Role",
"RBAC_Permission",
"Gateway_Chassis"
"Gateway_Chassis",
"IP_Multicast"
};


Expand Down Expand Up @@ -879,6 +880,7 @@ get_sb_ops(struct northd_ctx *ctx)
ddlog_table_update(&ds, ctx->ddlog, "OVN_Southbound", "DNS");
ddlog_table_update(&ds, ctx->ddlog, "OVN_Southbound", "RBAC_Role");
ddlog_table_update(&ds, ctx->ddlog, "OVN_Southbound", "RBAC_Permission");
ddlog_table_update(&ds, ctx->ddlog, "OVN_Southbound", "IP_Multicast");

ds_chomp(&ds, ',');

Expand Down

0 comments on commit 759cefc

Please sign in to comment.