#include "openvswitch/dynamic-string.h"
#include "encaps.h"
#include "fatal-signal.h"
-#include "hmap.h"
+#include "openvswitch/hmap.h"
#include "lflow.h"
#include "lib/vswitch-idl.h"
#include "lport.h"
#include "ofctrl.h"
#include "openvswitch/vconn.h"
#include "openvswitch/vlog.h"
+#include "ovn/lib/actions.h"
#include "ovn/lib/ovn-sb-idl.h"
+#include "ovn/lib/ovn-util.h"
#include "patch.h"
#include "physical.h"
#include "pinctrl.h"
#include "lib/bitmap.h"
#include "lib/hash.h"
#include "smap.h"
+#include "sset.h"
#include "stream-ssl.h"
#include "stream.h"
#include "unixctl.h"
static unixctl_cb_func ct_zone_list;
#define DEFAULT_BRIDGE_NAME "br-int"
+#define DEFAULT_PROBE_INTERVAL_MSEC 5000
+static void update_probe_interval(struct controller_ctx *);
static void parse_options(int argc, char *argv[]);
OVS_NO_RETURN static void usage(void);
}
}
-/* Retrieves the OVN Southbound remote's json session probe interval from the
- * "external-ids:ovn-remote-probe-interval" key in 'ovs_idl' and returns it.
- *
- * This function must be called after get_ovnsb_remote(). */
-static bool
-get_ovnsb_remote_probe_interval(struct ovsdb_idl *ovs_idl, int *value)
+static void
+update_ct_zones(struct sset *lports, struct hmap *patched_datapaths,
+ struct simap *ct_zones, unsigned long *ct_zone_bitmap)
{
- const struct ovsrec_open_vswitch *cfg = ovsrec_open_vswitch_first(ovs_idl);
- if (!cfg) {
- return false;
+ struct simap_node *ct_zone, *ct_zone_next;
+ int scan_start = 1;
+ struct patched_datapath *pd;
+ const char *user;
+ struct sset all_users = SSET_INITIALIZER(&all_users);
+
+ SSET_FOR_EACH(user, lports) {
+ sset_add(&all_users, user);
}
- const char *probe_interval =
- smap_get(&cfg->external_ids, "ovn-remote-probe-interval");
- if (probe_interval) {
- if (str_to_int(probe_interval, 10, value)) {
- return true;
+ /* Local patched datapath (gateway routers) need zones assigned. */
+ HMAP_FOR_EACH(pd, hmap_node, patched_datapaths) {
+ if (!pd->local) {
+ continue;
}
- VLOG_WARN("Invalid value for OVN remote probe interval: %s",
- probe_interval);
+ char *dnat = alloc_nat_zone_key(pd->key, "dnat");
+ char *snat = alloc_nat_zone_key(pd->key, "snat");
+ sset_add(&all_users, dnat);
+ sset_add(&all_users, snat);
+ free(dnat);
+ free(snat);
+ }
+
+ /* Delete zones that do not exist in above sset. */
+ SIMAP_FOR_EACH_SAFE(ct_zone, ct_zone_next, ct_zones) {
+ if (!sset_contains(&all_users, ct_zone->name)) {
+ bitmap_set0(ct_zone_bitmap, ct_zone->data);
+ simap_delete(ct_zones, ct_zone);
+ }
}
- return false;
+ /* xxx This is wasteful to assign a zone to each port--even if no
+ * xxx security policy is applied. */
+
+ /* Assign a unique zone id for each logical port and two zones
+ * to a gateway router. */
+ SSET_FOR_EACH(user, &all_users) {
+ size_t zone;
+
+ if (simap_contains(ct_zones, user)) {
+ continue;
+ }
+
+ /* We assume that there are 64K zones and that we own them all. */
+ zone = bitmap_scan(ct_zone_bitmap, 0, scan_start, MAX_CT_ZONES + 1);
+ if (zone == MAX_CT_ZONES + 1) {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ VLOG_WARN_RL(&rl, "exhausted all ct zones");
+ return;
+ }
+ scan_start = zone + 1;
+
+ bitmap_set1(ct_zone_bitmap, zone);
+ simap_put(ct_zones, user, zone);
+
+ /* xxx We should erase any old entries for this
+ * xxx zone, but we need a generic interface to the conntrack
+ * xxx table. */
+ }
+
+ sset_destroy(&all_users);
+}
+
+static int64_t
+get_nb_cfg(struct ovsdb_idl *idl)
+{
+ const struct sbrec_sb_global *sb = sbrec_sb_global_first(idl);
+ return sb ? sb->nb_cfg : 0;
}
+/* Contains "struct local_datapath" nodes whose hash values are the
+ * tunnel_key of datapaths with at least one local port binding. */
+static struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
+static struct hmap patched_datapaths = HMAP_INITIALIZER(&patched_datapaths);
+
+static struct lport_index lports;
+static struct mcgroup_index mcgroups;
+
int
main(int argc, char *argv[])
{
}
unixctl_command_register("exit", "", 0, 0, ovn_controller_exit, &exiting);
+ /* Initialize group ids for loadbalancing. */
+ struct group_table group_table;
+ group_table.group_ids = bitmap_allocate(MAX_OVN_GROUPS);
+ bitmap_set1(group_table.group_ids, 0); /* Group id 0 is invalid. */
+ hmap_init(&group_table.desired_groups);
+ hmap_init(&group_table.existing_groups);
+
daemonize_complete();
ovsrec_init();
pinctrl_init();
lflow_init();
+ lport_index_init(&lports);
+ mcgroup_index_init(&mcgroups);
+
/* Connect to OVS OVSDB instance. We do not monitor all tables by
* default, so modules must register their interest explicitly. */
struct ovsdb_idl_loop ovs_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
char *ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl);
struct ovsdb_idl_loop ovnsb_idl_loop = OVSDB_IDL_LOOP_INITIALIZER(
ovsdb_idl_create(ovnsb_remote, &sbrec_idl_class, true, true));
- ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
+ ovsdb_idl_omit_alert(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg);
- int probe_interval = 0;
- if (get_ovnsb_remote_probe_interval(ovs_idl_loop.idl, &probe_interval)) {
- ovsdb_idl_set_probe_interval(ovnsb_idl_loop.idl, probe_interval);
- }
+ /* Track the southbound idl. */
+ ovsdb_idl_track_add_all(ovnsb_idl_loop.idl);
+
+ ovsdb_idl_get_initial_snapshot(ovnsb_idl_loop.idl);
/* Initialize connection tracking zones. */
struct simap ct_zones = SIMAP_INITIALIZER(&ct_zones);
unsigned long ct_zone_bitmap[BITMAP_N_LONGS(MAX_CT_ZONES)];
+ memset(ct_zone_bitmap, 0, sizeof ct_zone_bitmap);
bitmap_set1(ct_zone_bitmap, 0); /* Zone 0 is reserved. */
unixctl_command_register("ct-zone-list", "", 0, 0,
ct_zone_list, &ct_zones);
free(ovnsb_remote);
ovnsb_remote = new_ovnsb_remote;
ovsdb_idl_set_remote(ovnsb_idl_loop.idl, ovnsb_remote, true);
+ binding_reset_processing();
+ lport_index_clear(&lports);
+ mcgroup_index_clear(&mcgroups);
} else {
free(new_ovnsb_remote);
}
.ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
};
- /* Contains "struct local_datpath" nodes whose hash values are the
- * tunnel_key of datapaths with at least one local port binding. */
- struct hmap local_datapaths = HMAP_INITIALIZER(&local_datapaths);
+ update_probe_interval(&ctx);
- struct hmap patched_datapaths = HMAP_INITIALIZER(&patched_datapaths);
+ struct sset all_lports = SSET_INITIALIZER(&all_lports);
const struct ovsrec_bridge *br_int = get_br_int(&ctx);
const char *chassis_id = get_chassis_id(ctx.ovs_idl);
+ const struct sbrec_chassis *chassis = NULL;
if (chassis_id) {
- chassis_run(&ctx, chassis_id);
+ chassis = chassis_run(&ctx, chassis_id);
encaps_run(&ctx, br_int, chassis_id);
- binding_run(&ctx, br_int, chassis_id, &ct_zones, ct_zone_bitmap,
- &local_datapaths);
+ binding_run(&ctx, br_int, chassis_id, &local_datapaths);
}
- if (br_int) {
- patch_run(&ctx, br_int, &local_datapaths, &patched_datapaths);
+ if (br_int && chassis_id) {
+ patch_run(&ctx, br_int, chassis_id, &local_datapaths,
+ &patched_datapaths);
- struct lport_index lports;
- struct mcgroup_index mcgroups;
- lport_index_init(&lports, ctx.ovnsb_idl);
- mcgroup_index_init(&mcgroups, ctx.ovnsb_idl);
+ lport_index_fill(&lports, ctx.ovnsb_idl);
+ mcgroup_index_fill(&mcgroups, ctx.ovnsb_idl);
enum mf_field_id mff_ovn_geneve = ofctrl_run(br_int);
- pinctrl_run(&ctx, &lports, br_int);
+ pinctrl_run(&ctx, &lports, br_int, chassis_id, &local_datapaths);
+ update_ct_zones(&all_lports, &patched_datapaths, &ct_zones,
+ ct_zone_bitmap);
- struct hmap flow_table = HMAP_INITIALIZER(&flow_table);
lflow_run(&ctx, &lports, &mcgroups, &local_datapaths,
- &patched_datapaths, &ct_zones, &flow_table);
- if (chassis_id) {
- physical_run(&ctx, mff_ovn_geneve,
- br_int, chassis_id, &ct_zones, &flow_table,
- &local_datapaths, &patched_datapaths);
+ &patched_datapaths, &group_table, &ct_zones);
+
+ physical_run(&ctx, mff_ovn_geneve,
+ br_int, chassis_id, &ct_zones,
+ &local_datapaths, &patched_datapaths);
+
+ ofctrl_put(&group_table, get_nb_cfg(ctx.ovnsb_idl));
+ if (ctx.ovnsb_idl_txn) {
+ int64_t cur_cfg = ofctrl_get_cur_cfg();
+ if (cur_cfg && cur_cfg != chassis->nb_cfg) {
+ sbrec_chassis_set_nb_cfg(chassis, cur_cfg);
+ }
}
- ofctrl_put(&flow_table);
- hmap_destroy(&flow_table);
- mcgroup_index_destroy(&mcgroups);
- lport_index_destroy(&lports);
}
- struct local_datapath *cur_node, *next_node;
- HMAP_FOR_EACH_SAFE (cur_node, next_node, hmap_node, &local_datapaths) {
- hmap_remove(&local_datapaths, &cur_node->hmap_node);
- free(cur_node);
- }
- hmap_destroy(&local_datapaths);
-
- struct patched_datapath *pd_cur_node, *pd_next_node;
- HMAP_FOR_EACH_SAFE (pd_cur_node, pd_next_node, hmap_node,
- &patched_datapaths) {
- hmap_remove(&patched_datapaths, &pd_cur_node->hmap_node);
- free(pd_cur_node);
- }
- hmap_destroy(&patched_datapaths);
+ sset_destroy(&all_lports);
unixctl_server_run(unixctl);
}
ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop);
+ ovsdb_idl_track_clear(ovnsb_idl_loop.idl);
poll_block();
if (should_service_stop()) {
exiting = true;
simap_destroy(&ct_zones);
+ bitmap_free(group_table.group_ids);
+ hmap_destroy(&group_table.desired_groups);
+
+ struct group_info *installed, *next_group;
+ HMAP_FOR_EACH_SAFE(installed, next_group, hmap_node,
+ &group_table.existing_groups) {
+ hmap_remove(&group_table.existing_groups, &installed->hmap_node);
+ ds_destroy(&installed->group);
+ free(installed);
+ }
+ hmap_destroy(&group_table.existing_groups);
+
ovsdb_idl_loop_destroy(&ovs_idl_loop);
ovsdb_idl_loop_destroy(&ovnsb_idl_loop);
unixctl_command_reply(conn, ds_cstr(&ds));
ds_destroy(&ds);
}
+
+/* Get the desired SB probe timer from the OVS database and configure it into
+ * the SB database. */
+static void
+update_probe_interval(struct controller_ctx *ctx)
+{
+ const struct ovsrec_open_vswitch *cfg
+ = ovsrec_open_vswitch_first(ctx->ovs_idl);
+ int interval = (cfg
+ ? smap_get_int(&cfg->external_ids,
+ "ovn-remote-probe-interval",
+ DEFAULT_PROBE_INTERVAL_MSEC)
+ : DEFAULT_PROBE_INTERVAL_MSEC);
+ ovsdb_idl_set_probe_interval(ctx->ovnsb_idl, interval);
+}