Skip to content

Commit

Permalink
ovn-controller-vtep: Add gateway module.
Browse files Browse the repository at this point in the history
This commit adds the gateway module to ovn-controller-vtep.  The
module will register the physical switches to ovnsb as chassis and
constantly update the "vtep_logical_switches" column in Chassis table.

Limitation (Recorded in TODO file):

- Do not support reading multiple tunnel ips of physical switch.

Signed-off-by: Alex Wang <alexw@nicira.com>
Acked-by: Russell Bryant <rbryant@redhat.com>
  • Loading branch information
yew011 committed Aug 11, 2015
1 parent a660eac commit 0c1e8a7
Show file tree
Hide file tree
Showing 7 changed files with 454 additions and 4 deletions.
6 changes: 6 additions & 0 deletions ovn/TODO
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,9 @@
Epstein et al., "What's the Difference? Efficient Set
Reconciliation Without Prior Context". (I'm not yet aware of
previous non-academic use of this technique.)

** Support multiple tunnel encapsulations in Chassis.

So far, both ovn-controller and ovn-controller-vtep only allow
chassis to have one tunnel encapsulation entry. We should extend
the implementation to support multiple tunnel encapsulations.
2 changes: 2 additions & 0 deletions ovn/controller-vtep/automake.mk
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
bin_PROGRAMS += ovn/controller-vtep/ovn-controller-vtep
ovn_controller_vtep_ovn_controller_vtep_SOURCES = \
ovn/controller-vtep/gateway.c \
ovn/controller-vtep/gateway.h \
ovn/controller-vtep/ovn-controller-vtep.c \
ovn/controller-vtep/ovn-controller-vtep.h
ovn_controller_vtep_ovn_controller_vtep_LDADD = ovn/lib/libovn.la lib/libopenvswitch.la vtep/libvtep.la
Expand Down
222 changes: 222 additions & 0 deletions ovn/controller-vtep/gateway.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/* Copyright (c) 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <config.h>
#include "gateway.h"

#include "lib/poll-loop.h"
#include "lib/simap.h"
#include "lib/sset.h"
#include "lib/util.h"
#include "openvswitch/vlog.h"
#include "ovn/lib/ovn-sb-idl.h"
#include "vtep/vtep-idl.h"
#include "ovn-controller-vtep.h"

VLOG_DEFINE_THIS_MODULE(gateway);

/*
* Registers the physical switches in vtep to ovnsb as chassis. For each
* physical switch in the vtep database, finds all vtep logical switches that
* are associated with the physical switch, and updates the corresponding
* chassis's 'vtep_logical_switches' column.
*
*/

/* Global revalidation sequence number, incremented at each call to
* 'revalidate_gateway()'. */
static unsigned int gw_reval_seq;

/* Maps all chassis created by the gateway module to their own reval_seq. */
static struct simap gw_chassis_map = SIMAP_INITIALIZER(&gw_chassis_map);

/* Creates and returns a new instance of 'struct sbrec_chassis'. */
static const struct sbrec_chassis *
create_chassis_rec(struct ovsdb_idl_txn *txn, const char *name,
const char *encap_ip)
{
const struct sbrec_chassis *chassis_rec;
struct sbrec_encap *encap_rec;

VLOG_INFO("add Chassis row for VTEP physical switch (%s)", name);

chassis_rec = sbrec_chassis_insert(txn);
sbrec_chassis_set_name(chassis_rec, name);
encap_rec = sbrec_encap_insert(txn);
sbrec_encap_set_type(encap_rec, OVN_SB_ENCAP_TYPE);
sbrec_encap_set_ip(encap_rec, encap_ip);
sbrec_chassis_set_encaps(chassis_rec, &encap_rec, 1);

return chassis_rec;
}

/* Revalidates chassis in ovnsb against vtep database. Creates chassis for
* new vtep physical switch. And removes chassis which no longer have
* physical switch in vtep.
*
* xxx: Support multiple tunnel encaps.
*
* */
static void
revalidate_gateway(struct controller_vtep_ctx *ctx)
{
const struct vteprec_physical_switch *pswitch;

/* Increments the global revalidation sequence number. */
gw_reval_seq++;

ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
"ovn-controller-vtep: updating vtep chassis");

VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
const struct sbrec_chassis *chassis_rec;
struct simap_node *gw_node;
const char *encap_ip;

encap_ip = pswitch->n_tunnel_ips ? pswitch->tunnel_ips[0] : "";
gw_node = simap_find(&gw_chassis_map, pswitch->name);
chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
if (chassis_rec) {
if (!gw_node &&
(strcmp(chassis_rec->encaps[0]->type, OVN_SB_ENCAP_TYPE)
|| strcmp(chassis_rec->encaps[0]->ip, encap_ip))) {
VLOG_WARN("Chassis config changing on startup, make sure "
"multiple chassis are not configured : %s/%s->%s/%s",
chassis_rec->encaps[0]->type,
chassis_rec->encaps[0]->ip,
OVN_SB_ENCAP_TYPE, encap_ip);
}
/* Updates chassis's encap if anything changed. */
if (strcmp(chassis_rec->encaps[0]->type, OVN_SB_ENCAP_TYPE)) {
VLOG_WARN("Chassis for VTEP physical switch (%s) can only have "
"encap type \"%s\"", pswitch->name, OVN_SB_ENCAP_TYPE);
sbrec_encap_set_type(chassis_rec->encaps[0], OVN_SB_ENCAP_TYPE);
}
if (strcmp(chassis_rec->encaps[0]->ip, encap_ip)) {
sbrec_encap_set_ip(chassis_rec->encaps[0], encap_ip);
}
} else {
if (gw_node) {
VLOG_WARN("Chassis for VTEP physical switch (%s) disappears, "
"maybe deleted by ovn-sbctl, adding it back",
pswitch->name);
}
/* Creates a new chassis for the VTEP physical switch. */
create_chassis_rec(ctx->ovnsb_idl_txn, pswitch->name, encap_ip);
}
/* Updates or creates the simap node for 'pswitch->name'. */
simap_put(&gw_chassis_map, pswitch->name, gw_reval_seq);
}

struct simap_node *iter, *next;
/* For 'gw_node' in 'gw_chassis_map' whose data is not
* 'gw_reval_seq', it means the corresponding physical switch no
* longer exist. So, garbage collects them. */
SIMAP_FOR_EACH_SAFE (iter, next, &gw_chassis_map) {
if (iter->data != gw_reval_seq) {
const struct sbrec_chassis *chassis_rec;

chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, iter->name);
if (chassis_rec) {
sbrec_chassis_delete(chassis_rec);
}
simap_delete(&gw_chassis_map, iter);
}
}
}

/* Updates the 'vtep_logical_switches' column in the Chassis table based
* on vtep database configuration. */
static void
update_vtep_logical_switches(struct controller_vtep_ctx *ctx)
{
const struct vteprec_physical_switch *pswitch;

ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, "ovn-controller-vtep: "
"updating chassis's vtep_logical_switches");

VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
const struct sbrec_chassis *chassis_rec =
get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
struct sset lswitches = SSET_INITIALIZER(&lswitches);
size_t i;

for (i = 0; i < pswitch->n_ports; i++) {
const struct vteprec_physical_port *port = pswitch->ports[i];
size_t j;

for (j = 0; j < port->n_vlan_bindings; j++) {
const struct vteprec_logical_switch *vtep_lswitch;

vtep_lswitch = port->value_vlan_bindings[j];
/* If not already in 'lswitches', records it. */
if (!sset_find(&lswitches, vtep_lswitch->name)) {
sset_add(&lswitches, vtep_lswitch->name);
}
}
}

const char **ls_arr = sset_array(&lswitches);
sbrec_chassis_set_vtep_logical_switches(chassis_rec, ls_arr,
sset_count(&lswitches));
free(ls_arr);
sset_destroy(&lswitches);
}
}


void
gateway_run(struct controller_vtep_ctx *ctx)
{
if (!ctx->ovnsb_idl_txn) {
return;
}

revalidate_gateway(ctx);
update_vtep_logical_switches(ctx);
}

/* Destroys the chassis table entries for vtep physical switches.
* Returns true when all done. */
bool
gateway_cleanup(struct controller_vtep_ctx *ctx)
{
static bool simap_destroyed = false;
const struct vteprec_physical_switch *pswitch;

if (!ctx->ovnsb_idl_txn) {
return false;
}

bool all_done = true;
ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn, "ovn-controller-vtep: "
"unregistering vtep chassis");
VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
const struct sbrec_chassis *chassis_rec;

chassis_rec = get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);
if (!chassis_rec) {
continue;
}
all_done = false;
sbrec_chassis_delete(chassis_rec);
}
if (!simap_destroyed) {
simap_destroy(&gw_chassis_map);
simap_destroyed = true;
}

return all_done;
}
26 changes: 26 additions & 0 deletions ovn/controller-vtep/gateway.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright (c) 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef OVN_GATEWAY_H
#define OVN_GATEWAY_H 1

#include <stdbool.h>

struct controller_vtep_ctx;

void gateway_run(struct controller_vtep_ctx *);
bool gateway_cleanup(struct controller_vtep_ctx *);

#endif /* ovn/controller-gw/gateway.h */
31 changes: 27 additions & 4 deletions ovn/controller-vtep/ovn-controller-vtep.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#include <stdlib.h>
#include <string.h>

#include "ovn-controller-vtep.h"

#include "command-line.h"
#include "compiler.h"
#include "daemon.h"
Expand All @@ -39,6 +37,9 @@
#include "ovn/lib/ovn-sb-idl.h"
#include "vtep/vtep-idl.h"

#include "gateway.h"
#include "ovn-controller-vtep.h"

static unixctl_cb_func ovn_controller_vtep_exit;

static void parse_options(int argc, char *argv[]);
Expand Down Expand Up @@ -86,13 +87,14 @@ main(int argc, char *argv[])
/* Main loop. */
exiting = false;
while (!exiting) {
struct controller_vtep_ctx OVS_UNUSED ctx = {
struct controller_vtep_ctx ctx = {
.vtep_idl = vtep_idl_loop.idl,
.vtep_idl_txn = ovsdb_idl_loop_run(&vtep_idl_loop),
.ovnsb_idl = ovnsb_idl_loop.idl,
.ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
};

gateway_run(&ctx);
unixctl_server_run(unixctl);

unixctl_server_wait(unixctl);
Expand All @@ -104,8 +106,29 @@ main(int argc, char *argv[])
poll_block();
}

unixctl_server_destroy(unixctl);
/* It's time to exit. Clean up the databases. */
bool done = false;
while (!done) {
struct controller_vtep_ctx ctx = {
.vtep_idl = vtep_idl_loop.idl,
.vtep_idl_txn = ovsdb_idl_loop_run(&vtep_idl_loop),
.ovnsb_idl = ovnsb_idl_loop.idl,
.ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop),
};

/* Run all of the cleanup functions, even if one of them returns false.
* We're done if all of them return true. */
done = gateway_cleanup(&ctx);
if (done) {
poll_immediate_wake();
}

ovsdb_idl_loop_commit_and_wait(&vtep_idl_loop);
ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop);
poll_block();
}

unixctl_server_destroy(unixctl);
ovsdb_idl_loop_destroy(&vtep_idl_loop);
ovsdb_idl_loop_destroy(&ovnsb_idl_loop);

Expand Down
20 changes: 20 additions & 0 deletions ovn/controller-vtep/ovn-controller-vtep.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#ifndef OVN_CONTROLLER_VTEP_H
#define OVN_CONTROLLER_VTEP_H 1

#include "ovn/lib/ovn-sb-idl.h"

struct ovsdb_idl;
struct ovsdb_idl_txn;

Expand All @@ -28,4 +30,22 @@ struct controller_vtep_ctx {
struct ovsdb_idl_txn *vtep_idl_txn;
};

/* VTEP needs what VTEP needs. */
#define OVN_SB_ENCAP_TYPE "vxlan"
#define VTEP_ENCAP_TYPE "vxlan_over_ipv4"

static inline const struct sbrec_chassis *
get_chassis_by_name(struct ovsdb_idl *ovnsb_idl, const char *chassis_id)
{
const struct sbrec_chassis *chassis_rec;

SBREC_CHASSIS_FOR_EACH(chassis_rec, ovnsb_idl) {
if (!strcmp(chassis_rec->name, chassis_id)) {
break;
}
}

return chassis_rec;
}

#endif /* ovn/ovn-controller-vtep.h */
Loading

0 comments on commit 0c1e8a7

Please sign in to comment.