Skip to content

Commit

Permalink
ovn-controller-vtep: Add binding module.
Browse files Browse the repository at this point in the history
This commit adds the binding module to ovn-controller-vtep.  The
module will scan through the Port_Binding table in ovnsb.  If there is
a port binding entry for a logical switch on the vtep gateway chassis's
"vtep_logical_switches", sets the port binding's chassis column to the
vtep gateway chassis.

Signed-off-by: Alex Wang <[email protected]>
Acked-by: Russell Bryant <[email protected]>
  • Loading branch information
yew011 committed Aug 17, 2015
1 parent dc4b6ff commit 6228d33
Show file tree
Hide file tree
Showing 5 changed files with 417 additions and 0 deletions.
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/binding.c \
ovn/controller-vtep/binding.h \
ovn/controller-vtep/gateway.c \
ovn/controller-vtep/gateway.h \
ovn/controller-vtep/ovn-controller-vtep.c \
Expand Down
269 changes: 269 additions & 0 deletions ovn/controller-vtep/binding.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
/* 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 "binding.h"

#include "lib/shash.h"
#include "lib/smap.h"
#include "lib/util.h"
#include "openvswitch/vlog.h"
#include "ovn-controller-vtep.h"
#include "ovn/lib/ovn-sb-idl.h"
#include "vtep/vtep-idl.h"

VLOG_DEFINE_THIS_MODULE(binding);

/*
* This module scans through the Port_Binding table in ovnsb. If there is a
* logical port binding entry for logical switch in vtep gateway chassis's
* 'vtep_logical_switches' column, sets the binding's chassis column to the
* corresponding vtep gateway chassis.
*
*/


/* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
* has already been bound to another port binding entry, and resets
* 'port_binding_rec''s chassis column. Otherwise, updates 'ls_to_pb'
* and returns false. */
static bool
check_pb_conflict(struct shash *ls_to_pb,
const struct sbrec_port_binding *port_binding_rec,
const char *chassis_name,
const char *vtep_lswitch)
{
const struct sbrec_port_binding *pb_conflict =
shash_find_data(ls_to_pb, vtep_lswitch);

if (pb_conflict) {
VLOG_WARN("logical switch (%s), on vtep gateway chassis "
"(%s) has already been associated with logical "
"port (%s), ignore logical port (%s)",
vtep_lswitch, chassis_name,
pb_conflict->logical_port,
port_binding_rec->logical_port);
sbrec_port_binding_set_chassis(port_binding_rec, NULL);

return true;
}

shash_add(ls_to_pb, vtep_lswitch, port_binding_rec);
return false;
}

/* Returns true if the 'vtep_lswitch' specified in 'port_binding_rec'
* has already been bound to a different datapath, and resets
* 'port_binding_rec''s chassis column. Otherwise, updates 'ls_to_db' and
* returns false. */
static bool
check_db_conflict(struct shash *ls_to_db,
const struct sbrec_port_binding *port_binding_rec,
const char *chassis_name,
const char *vtep_lswitch)
{
const struct sbrec_datapath_binding *db_conflict =
shash_find_data(ls_to_db, vtep_lswitch);

if (db_conflict && db_conflict != port_binding_rec->datapath) {
VLOG_WARN("logical switch (%s), on vtep gateway chassis "
"(%s) has already been associated with logical "
"datapath (with tunnel key %"PRId64"), ignore "
"logical port (%s) which belongs to logical "
"datapath (with tunnel key %"PRId64")",
vtep_lswitch, chassis_name,
db_conflict->tunnel_key,
port_binding_rec->logical_port,
port_binding_rec->datapath->tunnel_key);
sbrec_port_binding_set_chassis(port_binding_rec, NULL);

return true;
}

shash_replace(ls_to_db, vtep_lswitch, port_binding_rec->datapath);
return false;
}

/* Updates the 'port_binding_rec''s chassis column to 'chassis_rec'. */
static void
update_pb_chassis(const struct sbrec_port_binding *port_binding_rec,
const struct sbrec_chassis *chassis_rec)
{
if (port_binding_rec->chassis != chassis_rec) {
if (chassis_rec && port_binding_rec->chassis) {
VLOG_DBG("Changing chassis association of logical "
"port (%s) from (%s) to (%s)",
port_binding_rec->logical_port,
port_binding_rec->chassis->name,
chassis_rec->name);
}
sbrec_port_binding_set_chassis(port_binding_rec, chassis_rec);
}
}


/* Checks and updates logical port to vtep logical switch bindings for each
* physical switch in VTEP. */
void
binding_run(struct controller_vtep_ctx *ctx)
{
if (!ctx->ovnsb_idl_txn) {
return;
}

/* 'ls_to_db'
*
* Maps vtep logical switch name to the datapath binding entry. This is
* used to guarantee that each vtep logical switch is only included
* in only one ovn datapath (ovn logical switch). See check_db_conflict()
* for details.
*
* 'ls_to_pb'
*
* Maps vtep logical switch name to the port binding entry. This is used
* to guarantee that each vtep logical switch on a vtep physical switch
* is only bound to one logical port. See check_pb_conflict() for
* details.
*
*/
struct shash ls_to_db = SHASH_INITIALIZER(&ls_to_db);

/* Stores the 'chassis' and the 'ls_to_pb' map related to
* a vtep physcial switch. */
struct ps {
const struct sbrec_chassis *chassis_rec;
struct shash ls_to_pb;
};
struct shash ps_map = SHASH_INITIALIZER(&ps_map);
const struct vteprec_physical_switch *pswitch;
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 ps *ps = xmalloc(sizeof *ps);
size_t i;

/* 'chassis_rec' must exist. */
ovs_assert(chassis_rec);
ps->chassis_rec = chassis_rec;
shash_init(&ps->ls_to_pb);
for (i = 0; i < chassis_rec->n_vtep_logical_switches; i++) {
shash_add(&ps->ls_to_pb, chassis_rec->vtep_logical_switches[i],
NULL);
}
shash_add(&ps_map, chassis_rec->name, ps);
}

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

const struct sbrec_port_binding *port_binding_rec;
/* Port binding for vtep gateway chassis must have type "vtep",
* and matched physical switch name and logical switch name. */
SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
const char *type = port_binding_rec->type;
const char *vtep_pswitch = smap_get(&port_binding_rec->options,
"vtep-physical-switch");
const char *vtep_lswitch = smap_get(&port_binding_rec->options,
"vtep-logical-switch");
struct ps *ps
= vtep_pswitch ? shash_find_data(&ps_map, vtep_pswitch) : NULL;
bool found_ls
= ps && vtep_lswitch && shash_find(&ps->ls_to_pb, vtep_lswitch);

if (!strcmp(type, "vtep") && found_ls) {
bool pb_conflict, db_conflict;

pb_conflict = check_pb_conflict(&ps->ls_to_pb, port_binding_rec,
ps->chassis_rec->name,
vtep_lswitch);
db_conflict = check_db_conflict(&ls_to_db, port_binding_rec,
ps->chassis_rec->name,
vtep_lswitch);
/* Updates port binding's chassis column when there
* is no conflict. */
if (!pb_conflict && !db_conflict) {
update_pb_chassis(port_binding_rec, ps->chassis_rec);
}
} else if (port_binding_rec->chassis
&& shash_find(&ps_map, port_binding_rec->chassis->name)) {
/* Resets 'port_binding_rec' since it is no longer bound to
* any vtep logical switch. */
update_pb_chassis(port_binding_rec, NULL);
}
}

struct shash_node *iter, *next;
SHASH_FOR_EACH_SAFE (iter, next, &ps_map) {
struct ps *ps = iter->data;
struct shash_node *node;

SHASH_FOR_EACH (node, &ps->ls_to_pb) {
if (!node->data) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_DBG_RL(&rl, "No port binding entry for logical switch (%s)"
"on vtep gateway chassis (%s)", node->name,
ps->chassis_rec->name);
}
}
shash_delete(&ps_map, iter);
shash_destroy(&ps->ls_to_pb);
free(ps);
}
shash_destroy(&ls_to_db);
shash_destroy(&ps_map);
}

/* Removes all port binding association with vtep gateway chassis.
* Returns true when all done. */
bool
binding_cleanup(struct controller_vtep_ctx *ctx)
{
if (!ctx->ovnsb_idl_txn) {
return false;
}

struct shash ch_to_pb = SHASH_INITIALIZER(&ch_to_pb);
const struct sbrec_port_binding *port_binding_rec;
bool all_done = true;
/* Hashs all port binding entries using the associated chassis name. */
SBREC_PORT_BINDING_FOR_EACH(port_binding_rec, ctx->ovnsb_idl) {
if (port_binding_rec->chassis) {
shash_add(&ch_to_pb, port_binding_rec->chassis->name,
port_binding_rec);
}
}

ovsdb_idl_txn_add_comment(ctx->ovnsb_idl_txn,
"ovn-controller-vtep: removing bindings");

const struct vteprec_physical_switch *pswitch;
VTEPREC_PHYSICAL_SWITCH_FOR_EACH (pswitch, ctx->vtep_idl) {
const struct sbrec_chassis *chassis_rec
= get_chassis_by_name(ctx->ovnsb_idl, pswitch->name);

for (;;) {
port_binding_rec = shash_find_and_delete(&ch_to_pb,
chassis_rec->name);
if (!port_binding_rec) {
break;
}
all_done = false;
update_pb_chassis(port_binding_rec, NULL);
}
}
shash_destroy(&ch_to_pb);

return all_done;
}
27 changes: 27 additions & 0 deletions ovn/controller-vtep/binding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* 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_BINDING_H
#define OVN_BINDING_H 1

#include <stdbool.h>

struct controller_vtep_ctx;

void binding_run(struct controller_vtep_ctx *);
bool binding_cleanup(struct controller_vtep_ctx *);

#endif /* ovn/controller-gw/binding.h */
4 changes: 4 additions & 0 deletions ovn/controller-vtep/ovn-controller-vtep.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "ovn/lib/ovn-sb-idl.h"
#include "vtep/vtep-idl.h"

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

Expand Down Expand Up @@ -95,6 +96,7 @@ main(int argc, char *argv[])
};

gateway_run(&ctx);
binding_run(&ctx);
unixctl_server_run(unixctl);

unixctl_server_wait(unixctl);
Expand All @@ -119,6 +121,7 @@ main(int argc, char *argv[])
/* 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);
done = binding_cleanup(&ctx) && done;
if (done) {
poll_immediate_wake();
}
Expand All @@ -129,6 +132,7 @@ main(int argc, char *argv[])
}

unixctl_server_destroy(unixctl);

ovsdb_idl_loop_destroy(&vtep_idl_loop);
ovsdb_idl_loop_destroy(&ovnsb_idl_loop);

Expand Down
Loading

0 comments on commit 6228d33

Please sign in to comment.