2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

ofproto: Remove controller discovery support.

I've never heard of anyone actually using controller discovery.
It adds a great deal of code to the source tree, and a little
bit of complication to ofproto, so this commit removes it.
This commit is contained in:
Ben Pfaff
2011-03-15 09:46:39 -07:00
parent 9b45d7f5db
commit 195c808624
31 changed files with 40 additions and 3599 deletions

View File

@@ -118,10 +118,6 @@ OpenFlow switch.
contact the DHCP server until the secure channel has
started. The address will be obtained in step 7.
- If you are using in-band control with controller discovery, no
configuration is required at this point. You may proceed to
the next step.
6. Run ovs-openflowd to start the secure channel connecting the datapath to
a remote controller. If the controller is running on host
192.168.1.2 port 6633 (the default port), the ovs-openflowd invocation
@@ -129,9 +125,6 @@ OpenFlow switch.
# ovs-openflowd dp0 tcp:192.168.1.2
- If you are using in-band control with controller discovery, omit
the second argument to the ovs-openflowd command.
- If you are using out-of-band control, add --out-of-band to the
command line.
@@ -139,16 +132,13 @@ OpenFlow switch.
in an insecure manner. Please see INSTALL.SSL for a description of
how to connect securely using SSL.
7. If you are using in-band control with manual configuration, and the
switch obtains its IP address dynamically, then you may now obtain
the switch's IP address, e.g. by invoking a DHCP client. The
secure channel will only be able to connect to the controller after
an IP address has been obtained.
7. If you are using in-band control, and the switch obtains its IP address
dynamically, then you may now obtain the switch's IP address, e.g. by
invoking a DHCP client. The secure channel will only be able to connect
to the controller after an IP address has been obtained.
8. The secure channel should connect to the controller within a few
seconds. It may take a little longer if controller discovery is in
use, because the switch must then also obtain its own IP address
and the controller's location via DHCP.
seconds.
References
----------

View File

@@ -4,10 +4,4 @@ README.Debian for openvswitch-controller
* To (re)configure the controller, edit /etc/default/openvswitch-controller
and run "/etc/init.d/openvswitch-controller restart".
* To enable OpenFlow switches to automatically discover the location
of the controller, you must install and configure a DHCP server.
The ovs-openflowd(8) manpage (found in the openvswitch-switch
package) gives a working example configuration file for the ISC DHCP
server.
-- Ben Pfaff <blp@nicira.com>, Wed, 8 Jul 2009 09:39:53 -0700
-- Ben Pfaff <blp@nicira.com>, Fri, 4 Mar 2011 14:28:53 -0800

View File

@@ -1,5 +1,4 @@
_debian/ovsdb/ovsdb-server usr/bin
_debian/utilities/ovs-discover usr/sbin
_debian/utilities/ovs-dpctl usr/sbin
_debian/utilities/ovs-vsctl usr/sbin
_debian/utilities/ovs-pcap usr/bin

View File

@@ -1,5 +1,4 @@
_debian/ovsdb/ovsdb-server.1
_debian/utilities/ovs-discover.8
_debian/utilities/ovs-dpctl.8
_debian/utilities/ovs-pcap.1
_debian/utilities/ovs-tcpundump.1

View File

@@ -30,12 +30,9 @@ lib_libopenvswitch_a_SOURCES = \
lib/csum.h \
lib/daemon.c \
lib/daemon.h \
lib/dhcp.h \
lib/dummy.c \
lib/dummy.h \
lib/dhcp-client.c \
lib/dhcp-client.h \
lib/dhcp.c \
lib/dhcp.h \
lib/dhparams.h \
lib/dirs.h \
lib/dpif-netdev.c \

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +0,0 @@
/*
* Copyright (c) 2008, 2010 Nicira Networks.
*
* 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 DHCP_CLIENT_H
#define DHCP_CLIENT_H 1
#include <stdbool.h>
#include <stdint.h>
struct dhclient;
struct dhcp_msg;
struct netdev;
int dhclient_create(const char *netdev,
void (*modify_request)(struct dhcp_msg *, void *aux),
bool (*validate_offer)(const struct dhcp_msg *, void *aux),
void *aux, struct dhclient **);
void dhclient_set_max_timeout(struct dhclient *, unsigned int max_timeout);
void dhclient_destroy(struct dhclient *);
struct netdev *dhclient_get_netdev(struct dhclient *);
const char *dhclient_get_name(const struct dhclient *);
void dhclient_init(struct dhclient *, uint32_t requested_ip);
void dhclient_release(struct dhclient *);
void dhclient_force_renew(struct dhclient *, int deadline);
bool dhclient_is_bound(const struct dhclient *);
bool dhclient_changed(struct dhclient *);
const char *dhclient_get_state(const struct dhclient *);
unsigned int dhclient_get_state_elapsed(const struct dhclient *);
unsigned int dhclient_get_lease_remaining(const struct dhclient *);
uint32_t dhclient_get_ip(const struct dhclient *);
uint32_t dhclient_get_netmask(const struct dhclient *);
uint32_t dhclient_get_router(const struct dhclient *);
const struct dhcp_msg *dhclient_get_config(const struct dhclient *);
int dhclient_configure_netdev(struct dhclient *);
int dhclient_update_resolv_conf(struct dhclient *);
void dhclient_run(struct dhclient *);
void dhclient_wait(struct dhclient *);
#endif /* dhcp-client.h */

View File

@@ -1,824 +0,0 @@
/*
* Copyright (c) 2008, 2010 Nicira Networks.
*
* 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 "dhcp.h"
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include "dynamic-string.h"
#include "ofpbuf.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(dhcp);
/* Information about a DHCP argument type. */
struct arg_type {
const char *name; /* Name. */
size_t size; /* Number of bytes per argument. */
};
static struct arg_type types[] = {
#define DHCP_ARG(NAME, SIZE) [DHCP_ARG_##NAME] = {#NAME, SIZE},
DHCP_ARGS
#undef DHCP_ARG
};
/* Information about a DHCP option. */
struct option_class {
const char *name; /* Name. */
enum dhcp_arg_type type; /* Argument type. */
size_t min_args; /* Minimum number of arguments. */
size_t max_args; /* Maximum number of arguments. */
};
static const struct option_class *
get_option_class(int code)
{
static struct option_class classes[DHCP_N_OPTIONS];
static bool init = false;
if (!init) {
int i;
init = true;
#define DHCP_OPT(NAME, CODE, TYPE, MIN, MAX) \
classes[CODE].name = #NAME; \
classes[CODE].type = DHCP_ARG_##TYPE; \
classes[CODE].min_args = MIN; \
classes[CODE].max_args = MAX;
DHCP_OPTS
#undef DHCP_OPT
for (i = 0; i < DHCP_N_OPTIONS; i++) {
if (!classes[i].name) {
classes[i].name = xasprintf("option-%d", i);
classes[i].type = DHCP_ARG_UINT8;
classes[i].min_args = 0;
classes[i].max_args = SIZE_MAX;
}
}
}
assert(code >= 0 && code < DHCP_N_OPTIONS);
return &classes[code];
}
/* A single (bad) DHCP message can in theory dump out many, many log messages,
* especially at high logging levels, so the burst size is set quite high
* here to avoid missing useful information. */
struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 600);
static void copy_data(struct dhcp_msg *);
const char *
dhcp_type_name(enum dhcp_msg_type type)
{
switch (type) {
#define DHCP_MSG(NAME, VALUE) case NAME: return #NAME;
DHCP_MSGS
#undef DHCP_MSG
}
return "<<unknown DHCP message type>>";
}
/* Initializes 'msg' as a DHCP message. The message should be freed with
* dhcp_msg_uninit() when it is no longer needed. */
void
dhcp_msg_init(struct dhcp_msg *msg)
{
memset(msg, 0, sizeof *msg);
}
/* Frees the contents of 'msg'. The caller is responsible for freeing 'msg',
* if necessary. */
void
dhcp_msg_uninit(struct dhcp_msg *msg)
{
if (msg) {
free(msg->data);
}
}
/* Initializes 'dst' as a copy of 'src'. 'dst' (and 'src') should be freed
* with dhcp_msg_uninit() when it is no longer needed. */
void
dhcp_msg_copy(struct dhcp_msg *dst, const struct dhcp_msg *src)
{
*dst = *src;
dst->data_allocated = src->data_used;
dst->data_used = 0;
dst->data = xmalloc(dst->data_allocated);
copy_data(dst);
}
static void
prealloc_data(struct dhcp_msg *msg, size_t n)
{
size_t needed = msg->data_used + n;
if (needed > msg->data_allocated) {
uint8_t *old_data = msg->data;
msg->data_allocated = MAX(needed * 2, 64);
msg->data = xmalloc(msg->data_allocated);
if (old_data) {
copy_data(msg);
free(old_data);
}
}
}
static void *
append_data(struct dhcp_msg *msg, const void *data, size_t n)
{
uint8_t *p = &msg->data[msg->data_used];
memcpy(p, data, n);
msg->data_used += n;
return p;
}
static void
copy_data(struct dhcp_msg *msg)
{
int code;
msg->data_used = 0;
for (code = 0; code < DHCP_N_OPTIONS; code++) {
struct dhcp_option *opt = &msg->options[code];
if (opt->data) {
assert(msg->data_used + opt->n <= msg->data_allocated);
opt->data = append_data(msg, opt->data, opt->n);
}
}
}
/* Appends the 'n' bytes in 'data' to the DHCP option in 'msg' represented by
* 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put(struct dhcp_msg *msg, int code,
const void *data, size_t n)
{
struct dhcp_option *opt;
if (code == DHCP_CODE_PAD || code == DHCP_CODE_END) {
return;
}
opt = &msg->options[code];
prealloc_data(msg, n + opt->n);
if (opt->n) {
if (&msg->data[msg->data_used - opt->n] != opt->data) {
opt->data = append_data(msg, opt->data, opt->n);
}
append_data(msg, data, n);
} else {
opt->data = append_data(msg, data, n);
}
opt->n += n;
}
/* Appends the boolean value 'b', as a octet with value 0 (false) or 1 (true),
* to the DHCP option in 'msg' represented by 'code' (which must be in the
* range 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_bool(struct dhcp_msg *msg, int code, bool b_)
{
char b = !!b_;
dhcp_msg_put(msg, code, &b, 1);
}
/* Appends the number of seconds 'secs', as a 32-bit number in network byte
* order, to the DHCP option in 'msg' represented by 'code' (which must be in
* the range 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_secs(struct dhcp_msg *msg, int code, uint32_t secs_)
{
uint32_t secs = htonl(secs_);
dhcp_msg_put(msg, code, &secs, sizeof secs);
}
/* Appends the IP address 'ip', as a 32-bit number in network byte order, to
* the DHCP option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_ip(struct dhcp_msg *msg, int code, uint32_t ip)
{
dhcp_msg_put(msg, code, &ip, sizeof ip);
}
/* Appends the ASCII string 'string', to the DHCP option in 'msg' represented
* by 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_string(struct dhcp_msg *msg, int code, const char *string)
{
dhcp_msg_put(msg, code, string, strlen(string));
}
/* Appends octet 'x' to DHCP option in 'msg' represented by 'code' (which must
* be in the range 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_uint8(struct dhcp_msg *msg, int code, uint8_t x)
{
dhcp_msg_put(msg, code, &x, sizeof x);
}
/* Appends the 'n' octets in 'data' to DHCP option in 'msg' represented by
* 'code' (which must be in the range 0...DHCP_N_OPTIONS). */
void dhcp_msg_put_uint8_array(struct dhcp_msg *msg, int code,
const uint8_t data[], size_t n)
{
dhcp_msg_put(msg, code, data, n);
}
/* Appends the 16-bit value in 'x', in network byte order, to DHCP option in
* 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_uint16(struct dhcp_msg *msg, int code, uint16_t x_)
{
uint16_t x = htons(x_);
dhcp_msg_put(msg, code, &x, sizeof x);
}
/* Appends the 'n' 16-bit values in 'data', in network byte order, to DHCP
* option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). */
void
dhcp_msg_put_uint16_array(struct dhcp_msg *msg, int code,
const uint16_t data[], size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
dhcp_msg_put_uint16(msg, code, data[i]);
}
}
/* Returns a pointer to the 'size' bytes starting at byte offset 'offset' in
* the DHCP option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). If the option has fewer than 'offset + size' bytes,
* returns a null pointer. */
const void *
dhcp_msg_get(const struct dhcp_msg *msg, int code,
size_t offset, size_t size)
{
const struct dhcp_option *opt = &msg->options[code];
return offset + size <= opt->n ? (const char *) opt->data + offset : NULL;
}
/* Stores in '*out' the boolean value at byte offset 'offset' in the DHCP
* option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). Returns true if successful, false if the option has
* fewer than 'offset + 1' bytes. */
bool
dhcp_msg_get_bool(const struct dhcp_msg *msg, int code, size_t offset,
bool *out)
{
const uint8_t *uint8 = dhcp_msg_get(msg, code, offset, sizeof *uint8);
if (uint8) {
*out = *uint8 != 0;
return true;
} else {
return false;
}
}
/* Stores in '*out' the 32-bit count of seconds at offset 'offset' (in
* 4-byte increments) in the DHCP option in 'msg' represented by 'code'
* (which must be in the range 0...DHCP_N_OPTIONS). The value is converted to
* native byte order. Returns true if successful, false if the option has
* fewer than '4 * (offset + 1)' bytes. */
bool
dhcp_msg_get_secs(const struct dhcp_msg *msg, int code, size_t offset,
uint32_t *out)
{
const uint32_t *uint32 = dhcp_msg_get(msg, code, offset * sizeof *uint32,
sizeof *uint32);
if (uint32) {
*out = ntohl(*uint32);
return true;
} else {
return false;
}
}
/* Stores in '*out' the IP address at offset 'offset' (in 4-byte increments) in
* the DHCP option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). The IP address is stored in network byte order.
* Returns true if successful, false if the option has fewer than '4 * (offset
* + 1)' bytes. */
bool
dhcp_msg_get_ip(const struct dhcp_msg *msg, int code,
size_t offset, uint32_t *out)
{
const uint32_t *uint32 = dhcp_msg_get(msg, code, offset * sizeof *uint32,
sizeof *uint32);
if (uint32) {
*out = *uint32;
return true;
} else {
return false;
}
}
/* Returns the string in the DHCP option in 'msg' represented by 'code' (which
* must be in the range 0...DHCP_N_OPTIONS). The caller is responsible for
* freeing the string with free().
*
* If 'msg' has no option represented by 'code', returns a null pointer. (If
* the option was specified but had no content, then an empty string is
* returned, not a null pointer.) */
char *
dhcp_msg_get_string(const struct dhcp_msg *msg, int code)
{
const struct dhcp_option *opt = &msg->options[code];
return opt->data ? xmemdup0(opt->data, opt->n) : NULL;
}
/* Stores in '*out' the octet at byte offset 'offset' in the DHCP option in
* 'msg' represented by 'code' (which must be in the range 0...DHCP_N_OPTIONS).
* Returns true if successful, false if the option has fewer than 'offset + 1'
* bytes. */
bool
dhcp_msg_get_uint8(const struct dhcp_msg *msg, int code,
size_t offset, uint8_t *out)
{
const uint8_t *uint8 = dhcp_msg_get(msg, code, offset, sizeof *uint8);
if (uint8) {
*out = *uint8;
return true;
} else {
return false;
}
}
/* Stores in '*out' the 16-bit value at offset 'offset' (in 2-byte units) in
* the DHCP option in 'msg' represented by 'code' (which must be in the range
* 0...DHCP_N_OPTIONS). The value is converted to native byte order. Returns
* true if successful, false if the option has fewer than '2 * (offset + 1)'
* bytes. */
bool
dhcp_msg_get_uint16(const struct dhcp_msg *msg, int code,
size_t offset, uint16_t *out)
{
const uint16_t *uint16 = dhcp_msg_get(msg, code, offset * sizeof *uint16,
sizeof *uint16);
if (uint16) {
*out = ntohs(*uint16);
return true;
} else {
return false;
}
}
/* Appends a string representing 'duration' seconds to 'ds'. */
static void
put_duration(struct ds *ds, unsigned int duration)
{
if (duration) {
if (duration >= 86400) {
ds_put_format(ds, "%ud", duration / 86400);
duration %= 86400;
}
if (duration >= 3600) {
ds_put_format(ds, "%uh", duration / 3600);
duration %= 3600;
}
if (duration >= 60) {
ds_put_format(ds, "%umin", duration / 60);
duration %= 60;
}
if (duration > 0) {
ds_put_format(ds, "%us", duration);
}
} else {
ds_put_cstr(ds, "0s");
}
}
/* Appends a string representation of 'opt', which has the given 'code', to
* 'ds'. */
const char *
dhcp_option_to_string(const struct dhcp_option *opt, int code, struct ds *ds)
{
const struct option_class *class = get_option_class(code);
const struct arg_type *type = &types[class->type];
size_t offset;
const char *cp;
for (cp = class->name; *cp; cp++) {
unsigned char c = *cp;
ds_put_char(ds, c == '_' ? '-' : tolower(c));
}
ds_put_char(ds, '=');
if (!opt->data || !opt->n) {
ds_put_cstr(ds, opt->data ? "empty" : "null");
return ds_cstr(ds);
}
if (class->type == DHCP_ARG_STRING) {
ds_put_char(ds, '"');
ds_put_printable(ds, opt->data, opt->n);
ds_put_char(ds, '"');
return ds_cstr(ds);
}
for (offset = 0; offset + type->size <= opt->n; offset += type->size) {
const void *p = (const char *) opt->data + offset;
const uint8_t *uint8 = p;
const uint32_t *uint32 = p;
const uint16_t *uint16 = p;
if (offset && class->type != DHCP_ARG_STRING) {
ds_put_cstr(ds, class->type == DHCP_ARG_UINT8 ? ":" : ", ");
}
switch (class->type) {
case DHCP_ARG_FIXED:
NOT_REACHED();
case DHCP_ARG_IP:
ds_put_format(ds, IP_FMT, IP_ARGS(uint32));
break;
case DHCP_ARG_UINT8:
ds_put_format(ds, "%02"PRIx8, *uint8);
break;
case DHCP_ARG_UINT16:
ds_put_format(ds, "%"PRIu16, ntohs(*uint16));
break;
case DHCP_ARG_UINT32:
ds_put_format(ds, "%"PRIu32, ntohl(*uint32));
break;
case DHCP_ARG_SECS:
put_duration(ds, ntohl(*uint32));
break;
case DHCP_ARG_STRING:
NOT_REACHED();
case DHCP_ARG_BOOLEAN:
if (*uint8 == 0) {
ds_put_cstr(ds, "false");
} else if (*uint8 == 1) {
ds_put_cstr(ds, "true");
} else {
ds_put_format(ds, "**%"PRIu8"**", *uint8);
}
break;
}
}
if (offset != opt->n) {
if (offset) {
ds_put_cstr(ds, ", ");
}
ds_put_cstr(ds, "**leftovers:");
for (; offset < opt->n; offset++) {
const void *p = (const char *) opt->data + offset;
const uint8_t *uint8 = p;
ds_put_format(ds, " %"PRIu8, *uint8);
}
ds_put_cstr(ds, "**");
}
return ds_cstr(ds);
}
/* Returns true if 'a' and 'b' have the same content, false otherwise. */
bool
dhcp_option_equals(const struct dhcp_option *a, const struct dhcp_option *b)
{
return ((a->data != NULL) == (b->data != NULL)
&& a->n == b->n
&& (!a->data || !memcmp(a->data, b->data, a->n)));
}
/* Replaces 'ds' by a string representation of 'msg'. If 'multiline' is
* false, 'ds' receives a single-line representation of 'msg', otherwise a
* multiline representation. */
const char *
dhcp_msg_to_string(const struct dhcp_msg *msg, bool multiline, struct ds *ds)
{
char separator = multiline ? '\n' : ' ';
int code;
ds_clear(ds);
ds_put_format(ds, "op=%s",
(msg->op == DHCP_BOOTREQUEST ? "request"
: msg->op == DHCP_BOOTREPLY ? "reply"
: "error"));
ds_put_format(ds, "%ctype=%s", separator, dhcp_type_name(msg->type));
ds_put_format(ds, "%cxid=0x%08"PRIx32, separator, msg->xid);
ds_put_format(ds, "%csecs=", separator);
put_duration(ds, msg->secs);
if (msg->flags) {
ds_put_format(ds, "%cflags=", separator);
if (msg->flags & DHCP_FLAGS_BROADCAST) {
ds_put_cstr(ds, "[BROADCAST]");
}
if (msg->flags & DHCP_FLAGS_MBZ) {
ds_put_format(ds, "[0x%04"PRIx16"]", msg->flags & DHCP_FLAGS_MBZ);
}
}
if (msg->ciaddr) {
ds_put_format(ds, "%cciaddr="IP_FMT, separator, IP_ARGS(&msg->ciaddr));
}
if (msg->yiaddr) {
ds_put_format(ds, "%cyiaddr="IP_FMT, separator, IP_ARGS(&msg->yiaddr));
}
if (msg->siaddr) {
ds_put_format(ds, "%csiaddr="IP_FMT, separator, IP_ARGS(&msg->siaddr));
}
if (msg->giaddr) {
ds_put_format(ds, "%cgiaddr="IP_FMT, separator, IP_ARGS(&msg->giaddr));
}
ds_put_format(ds, "%cchaddr="ETH_ADDR_FMT,
separator, ETH_ADDR_ARGS(msg->chaddr));
for (code = 0; code < DHCP_N_OPTIONS; code++) {
const struct dhcp_option *opt = &msg->options[code];
if (opt->data) {
ds_put_char(ds, separator);
dhcp_option_to_string(opt, code, ds);
}
}
if (multiline) {
ds_put_char(ds, separator);
}
return ds_cstr(ds);
}
static void
parse_options(struct dhcp_msg *msg, const char *name, void *data, size_t size,
int option_offset)
{
struct ofpbuf b;
ofpbuf_use_const(&b, data, size);
for (;;) {
uint8_t *code, *len;
void *payload;
code = ofpbuf_try_pull(&b, 1);
if (!code || *code == DHCP_CODE_END) {
break;
} else if (*code == DHCP_CODE_PAD) {
continue;
}
len = ofpbuf_try_pull(&b, 1);
if (!len) {
VLOG_DBG_RL(&rl, "reached end of %s expecting length byte", name);
break;
}
payload = ofpbuf_try_pull(&b, *len);
if (!payload) {
VLOG_DBG_RL(&rl, "expected %"PRIu8" bytes of option-%"PRIu8" "
"payload with only %zu bytes of %s left",
*len, *code, b.size, name);
break;
}
dhcp_msg_put(msg, *code + option_offset, payload, *len);
}
}
static void
validate_options(struct dhcp_msg *msg)
{
int code;
for (code = 0; code < DHCP_N_OPTIONS; code++) {
struct dhcp_option *opt = &msg->options[code];
const struct option_class *class = get_option_class(code);
struct arg_type *type = &types[class->type];
if (opt->data) {
size_t n_elems = opt->n / type->size;
size_t remainder = opt->n % type->size;
bool ok = true;
if (remainder) {
VLOG_DBG_RL(&rl, "%s option has %zu %zu-byte %s arguments "
"with %zu bytes left over",
class->name, n_elems, type->size,
type->name, remainder);
ok = false;
}
if (n_elems < class->min_args || n_elems > class->max_args) {
VLOG_DBG_RL(&rl, "%s option has %zu %zu-byte %s arguments but "
"between %zu and %zu are required",
class->name, n_elems, type->size, type->name,
class->min_args, class->max_args);
ok = false;
}
if (!ok) {
struct ds ds = DS_EMPTY_INITIALIZER;
VLOG_DBG_RL(&rl, "%s option contains: %s", class->name,
dhcp_option_to_string(opt, code, &ds));
ds_destroy(&ds);
opt->n = 0;
opt->data = NULL;
}
}
}
}
/* Attempts to parse 'b' as a DHCP message. If successful, initializes '*msg'
* to the parsed message and returns 0. Otherwise, returns a positive errno
* value and '*msg' is indeterminate. */
int
dhcp_parse(struct dhcp_msg *msg, const struct ofpbuf *b_)
{
struct ofpbuf b = *b_;
struct dhcp_header *dhcp;
uint32_t *cookie;
uint8_t type;
char *vendor_class;
dhcp = ofpbuf_try_pull(&b, sizeof *dhcp);
if (!dhcp) {
VLOG_DBG_RL(&rl, "buffer too small for DHCP header (%zu bytes)",
b.size);
goto error;
}
if (dhcp->op != DHCP_BOOTREPLY && dhcp->op != DHCP_BOOTREQUEST) {
VLOG_DBG_RL(&rl, "invalid DHCP op (%"PRIu8")", dhcp->op);
goto error;
}
if (dhcp->htype != ARP_HRD_ETHERNET) {
VLOG_DBG_RL(&rl, "invalid DHCP htype (%"PRIu8")", dhcp->htype);
goto error;
}
if (dhcp->hlen != ETH_ADDR_LEN) {
VLOG_DBG_RL(&rl, "invalid DHCP hlen (%"PRIu8")", dhcp->hlen);
goto error;
}
dhcp_msg_init(msg);
msg->op = dhcp->op;
msg->xid = ntohl(dhcp->xid);
msg->secs = ntohs(dhcp->secs);
msg->flags = ntohs(dhcp->flags);
msg->ciaddr = dhcp->ciaddr;
msg->yiaddr = dhcp->yiaddr;
msg->siaddr = dhcp->siaddr;
msg->giaddr = dhcp->giaddr;
memcpy(msg->chaddr, dhcp->chaddr, ETH_ADDR_LEN);
cookie = ofpbuf_try_pull(&b, sizeof *cookie);
if (cookie) {
if (ntohl(*cookie) == DHCP_OPTS_COOKIE) {
uint8_t overload;
parse_options(msg, "options", b.data, b.size, 0);
if (dhcp_msg_get_uint8(msg, DHCP_CODE_OPTION_OVERLOAD,
0, &overload)) {
if (overload & 1) {
parse_options(msg, "file", dhcp->file, sizeof dhcp->file,
0);
}
if (overload & 2) {
parse_options(msg, "sname",
dhcp->sname, sizeof dhcp->sname, 0);
}
}
} else {
VLOG_DBG_RL(&rl, "bad DHCP options cookie: %08"PRIx32,
ntohl(*cookie));
}
} else {
VLOG_DBG_RL(&rl, "DHCP packet has no options");
}
vendor_class = dhcp_msg_get_string(msg, DHCP_CODE_VENDOR_CLASS);
if (vendor_class && !strcmp(vendor_class, "OpenFlow")) {
parse_options(msg, "vendor-specific",
msg->options[DHCP_CODE_VENDOR_SPECIFIC].data,
msg->options[DHCP_CODE_VENDOR_SPECIFIC].n,
DHCP_VENDOR_OFS);
}
free(vendor_class);
validate_options(msg);
if (!dhcp_msg_get_uint8(msg, DHCP_CODE_DHCP_MSG_TYPE, 0, &type)) {
VLOG_DBG_RL(&rl, "missing DHCP message type");
dhcp_msg_uninit(msg);
goto error;
}
msg->type = type;
return 0;
error:
if (VLOG_IS_DBG_ENABLED()) {
struct ds ds;
ds_init(&ds);
ds_put_hex_dump(&ds, b_->data, b_->size, 0, true);
VLOG_DBG_RL(&rl, "invalid DHCP message dump:\n%s", ds_cstr(&ds));
ds_clear(&ds);
dhcp_msg_to_string(msg, false, &ds);
VLOG_DBG_RL(&rl, "partially dissected DHCP message: %s", ds_cstr(&ds));
ds_destroy(&ds);
}
return EPROTO;
}
static void
put_option_chunk(struct ofpbuf *b, uint8_t code, void *data, size_t n)
{
uint8_t header[2];
assert(n < 256);
header[0] = code;
header[1] = n;
ofpbuf_put(b, header, sizeof header);
ofpbuf_put(b, data, n);
}
static void
put_option(struct ofpbuf *b, uint8_t code, void *data, size_t n)
{
if (data) {
if (n) {
/* Divide the data into chunks of 255 bytes or less. Make
* intermediate chunks multiples of 8 bytes in case the
* recipient validates a chunk at a time instead of the
* concatenated value. */
uint8_t *p = data;
while (n) {
size_t chunk = n > 255 ? 248 : n;
put_option_chunk(b, code, p, chunk);
p += chunk;
n -= chunk;
}
} else {
/* Option should be present but carry no data. */
put_option_chunk(b, code, NULL, 0);
}
}
}
/* Appends to 'b' the DHCP message represented by 'msg'. */
void
dhcp_assemble(const struct dhcp_msg *msg, struct ofpbuf *b)
{
const uint8_t end = DHCP_CODE_END;
uint32_t cookie = htonl(DHCP_OPTS_COOKIE);
struct ofpbuf vnd_data;
struct dhcp_header dhcp;
int i;
memset(&dhcp, 0, sizeof dhcp);
dhcp.op = msg->op;
dhcp.htype = ARP_HRD_ETHERNET;
dhcp.hlen = ETH_ADDR_LEN;
dhcp.hops = 0;
dhcp.xid = htonl(msg->xid);
dhcp.secs = htons(msg->secs);
dhcp.flags = htons(msg->flags);
dhcp.ciaddr = msg->ciaddr;
dhcp.yiaddr = msg->yiaddr;
dhcp.siaddr = msg->siaddr;
dhcp.giaddr = msg->giaddr;
memcpy(dhcp.chaddr, msg->chaddr, ETH_ADDR_LEN);
ofpbuf_put(b, &dhcp, sizeof dhcp);
ofpbuf_put(b, &cookie, sizeof cookie);
/* Put DHCP message type first. (The ordering is not required but it
* seems polite.) */
if (msg->type) {
uint8_t type = msg->type;
put_option(b, DHCP_CODE_DHCP_MSG_TYPE, &type, 1);
}
/* Put the standard options. */
for (i = 0; i < DHCP_VENDOR_OFS; i++) {
const struct dhcp_option *option = &msg->options[i];
put_option(b, i, option->data, option->n);
}
/* Assemble vendor specific option and put it. */
ofpbuf_init(&vnd_data, 0);
for (i = DHCP_VENDOR_OFS; i < DHCP_N_OPTIONS; i++) {
const struct dhcp_option *option = &msg->options[i];
put_option(&vnd_data, i - DHCP_VENDOR_OFS, option->data, option->n);
}
if (vnd_data.size) {
put_option(b, DHCP_CODE_VENDOR_SPECIFIC, vnd_data.data, vnd_data.size);
}
ofpbuf_uninit(&vnd_data);
/* Put end-of-options option. */
ofpbuf_put(b, &end, sizeof end);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008 Nicira Networks.
* Copyright (c) 2008, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,24 +21,10 @@
#include "packets.h"
#include "util.h"
struct ds;
struct ofpbuf;
/* Ports used by DHCP. */
#define DHCP_SERVER_PORT 67 /* Port used by DHCP server. */
#define DHCP_CLIENT_PORT 68 /* Port used by DHCP client. */
/* Values for 'op' field. */
#define DHCP_BOOTREQUEST 1 /* Message sent by DHCP client. */
#define DHCP_BOOTREPLY 2 /* Message sent by DHCP server. */
/* Bits in 'flags' field. */
#define DHCP_FLAGS_BROADCAST 0x8000 /* Server must broadcast all replies. */
#define DHCP_FLAGS_MBZ 0x7fff /* Must be zero. */
/* First four bytes of 'options' field. */
#define DHCP_OPTS_COOKIE 0x63825363
#define DHCP_HEADER_LEN 236
struct dhcp_header {
uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */
@@ -59,208 +45,4 @@ struct dhcp_header {
};
BUILD_ASSERT_DECL(DHCP_HEADER_LEN == sizeof(struct dhcp_header));
#define DHCP_ARGS \
DHCP_ARG(FIXED, 0) /* Fixed-length option (PAD and END only). */ \
DHCP_ARG(IP, 4) /* IP addresses. */ \
DHCP_ARG(SECS, 4) /* 32-bit duration in seconds. */ \
DHCP_ARG(STRING, 1) /* NVT string, optionally null-terminated. */ \
DHCP_ARG(UINT8, 1) /* 8-bit unsigned integer. */ \
DHCP_ARG(UINT16, 2) /* 16-bit unsigned integer. */ \
DHCP_ARG(UINT32, 4) /* 32-bit unsigned integer. */ \
DHCP_ARG(BOOLEAN, 1) /* Boolean octet (0 or 1). */
/* DHCP option argument types. */
enum dhcp_arg_type {
#define DHCP_ARG(NAME, SIZE) DHCP_ARG_##NAME,
DHCP_ARGS
#undef DHCP_ARG
};
#define DHCP_MSGS \
DHCP_MSG(DHCPDISCOVER, 1) /* Client->server: What IPs are available? */ \
DHCP_MSG(DHCPOFFER, 2) /* Server->client: This IP is available. */ \
DHCP_MSG(DHCPREQUEST, 3) /* Client->server: I want that IP. */ \
DHCP_MSG(DHCPDECLINE, 4) /* Client->server: That IP is in use!. */ \
DHCP_MSG(DHCPACK, 5) /* Server->client: You can have that IP. */ \
DHCP_MSG(DHCPNAK, 6) /* Server->client: You can't have that IP. */ \
DHCP_MSG(DHCPRELEASE, 7) /* Client->server: I'm done with this IP. */ \
DHCP_MSG(DCHPINFORM, 8) /* Client->server: I'm using this IP. */
/* DHCP message type (this is the argument for the DHCP_MSG_TYPE option). */
enum dhcp_msg_type {
#define DHCP_MSG(NAME, VALUE) NAME = VALUE,
DHCP_MSGS
#undef DHCP_MSG
};
const char *dhcp_type_name(enum dhcp_msg_type);
/* DHCP allows for 256 standardized options and 256 vendor-specific options.
* We put them in a single array, with the standard options at the
* beginning. */
#define DHCP_N_OPTIONS 512
#define DHCP_VENDOR_OFS 256
/* DHCP options. */
#define DHCP_OPTS \
/* arg min max */ \
/* name code type args args */ \
DHCP_OPT(PAD, 0, FIXED, 0, 0) \
DHCP_OPT(END, 255, FIXED, 0, 0) \
DHCP_OPT(SUBNET_MASK, 1, IP, 1, 1) \
DHCP_OPT(TIME_OFFSET, 2, SECS, 1, 1) \
DHCP_OPT(ROUTER, 3, IP, 1, SIZE_MAX) \
/* Time Server Option is obsolete. */ \
/* Name Server Option is obsolete. */ \
DHCP_OPT(DNS_SERVER, 6, IP, 1, SIZE_MAX) \
/* Log Server Option is obsolete. */ \
/* Cookie Server Option is obsolete. */ \
DHCP_OPT(LPR_SERVER, 9, IP, 1, SIZE_MAX) \
/* Impress Server Option is obsolete. */ \
/* Resource Location Server Option is obsolete. */ \
DHCP_OPT(HOST_NAME, 12, STRING, 1, SIZE_MAX) \
DHCP_OPT(BOOT_FILE_SIZE, 13, UINT16, 1, 1) \
/* Merit Dump File option is obsolete. */ \
DHCP_OPT(DOMAIN_NAME, 15, STRING, 1, SIZE_MAX) \
/* Swap Server option is obsolete. */ \
DHCP_OPT(ROOT_PATH, 17, STRING, 1, SIZE_MAX) \
DHCP_OPT(EXTENSIONS_PATH, 18, STRING, 1, SIZE_MAX) \
DHCP_OPT(IP_FORWARDING, 19, BOOLEAN, 1, 1) \
DHCP_OPT(SOURCE_ROUTING, 20, BOOLEAN, 1, 1) \
DHCP_OPT(POLICY_FILTER, 21, IP, 2, SIZE_MAX) \
DHCP_OPT(MAX_DGRAM_REASSEMBLY, 22, UINT16, 1, 1) \
DHCP_OPT(IP_TTL, 23, UINT8, 1, 1) \
DHCP_OPT(PATH_MTU_TIMEOUT, 24, SECS, 1, 1) \
DHCP_OPT(PATH_MTU_PLATEAU, 25, UINT16, 2, SIZE_MAX) \
DHCP_OPT(MTU, 26, UINT16, 1, 1) \
DHCP_OPT(ALL_SUBNETS_ARE_LOCAL, 27, BOOLEAN, 1, 1) \
DHCP_OPT(BROADCAST_ADDRESS, 28, IP, 1, 1) \
DHCP_OPT(PERFORM_MASK_DISCOVERY, 29, BOOLEAN, 1, 1) \
DHCP_OPT(MASK_SUPPLIER, 30, BOOLEAN, 1, 1) \
DHCP_OPT(PERFORM_ROUTER_DISCOVERY, 31, BOOLEAN, 1, 1) \
DHCP_OPT(ROUTER_SOLICITATION, 32, IP, 1, 1) \
DHCP_OPT(STATIC_ROUTE, 33, IP, 2, SIZE_MAX) \
/* Trailer Encapsulation Option is obsolete. */ \
DHCP_OPT(ARP_CACHE_TIMEOUT, 35, SECS, 1, 1) \
DHCP_OPT(ETHERNET_ENCAPSULATION, 36, BOOLEAN, 1, 1) \
DHCP_OPT(TCP_TTL, 37, UINT8, 1, 1) \
DHCP_OPT(TCP_KEEPALIVE_INTERVAL, 38, SECS, 1, 1) \
DHCP_OPT(TCP_KEEPALIVE_GARBAGE, 39, BOOLEAN, 1, 1) \
DHCP_OPT(NIS_DOMAIN, 40, STRING, 1, SIZE_MAX) \
DHCP_OPT(NIS_SERVERS, 41, IP, 1, SIZE_MAX) \
DHCP_OPT(NTP_SERVERS, 42, IP, 1, SIZE_MAX) \
DHCP_OPT(VENDOR_SPECIFIC, 43, UINT8, 1, SIZE_MAX) \
DHCP_OPT(NETBIOS_NS, 44, IP, 1, SIZE_MAX) \
DHCP_OPT(NETBIOS_DDS, 45, IP, 1, SIZE_MAX) \
DHCP_OPT(NETBIOS_NODE_TYPE, 46, UINT8, 1, 1) \
DHCP_OPT(NETBIOS_SCOPE, 47, STRING, 1, SIZE_MAX) \
DHCP_OPT(X_FONT_SERVER, 48, IP, 1, SIZE_MAX) \
DHCP_OPT(XDM, 49, IP, 1, SIZE_MAX) \
DHCP_OPT(NISPLUS_DOMAIN, 64, STRING, 1, SIZE_MAX) \
DHCP_OPT(NISPLUS_SERVERS, 65, IP, 1, SIZE_MAX) \
DHCP_OPT(MOBILE_IP_HOME_AGENT, 68, IP, 0, SIZE_MAX) \
DHCP_OPT(SMTP_SERVER, 69, IP, 1, SIZE_MAX) \
DHCP_OPT(POP3_SERVER, 70, IP, 1, SIZE_MAX) \
DHCP_OPT(NNTP_SERVER, 71, IP, 1, SIZE_MAX) \
DHCP_OPT(WWW_SERVER, 72, IP, 1, SIZE_MAX) \
DHCP_OPT(FINGER_SERVER, 73, IP, 1, SIZE_MAX) \
DHCP_OPT(IRC_SERVER, 74, IP, 1, SIZE_MAX) \
/* StreetTalk Server Option is obsolete. */ \
/* StreetTalk Directory Assistance Server Option is obsolete. */ \
DHCP_OPT(REQUESTED_IP, 50, IP, 1, 1) \
DHCP_OPT(LEASE_TIME, 51, SECS, 1, 1) \
DHCP_OPT(OPTION_OVERLOAD, 52, UINT8, 1, 1) \
DHCP_OPT(TFTP_SERVER, 66, STRING, 1, SIZE_MAX) \
DHCP_OPT(BOOTFILE_NAME, 67, STRING, 1, SIZE_MAX) \
DHCP_OPT(DHCP_MSG_TYPE, 53, UINT8, 1, 1) \
DHCP_OPT(SERVER_IDENTIFIER, 54, IP, 1, 1) \
DHCP_OPT(PARAMETER_REQUEST_LIST, 55, UINT8, 1, SIZE_MAX) \
DHCP_OPT(MESSAGE, 56, STRING, 1, SIZE_MAX) \
DHCP_OPT(MAX_DHCP_MSG_SIZE, 57, UINT16, 1, 1) \
DHCP_OPT(T1, 58, SECS, 1, 1) \
DHCP_OPT(T2, 59, SECS, 1, 1) \
DHCP_OPT(VENDOR_CLASS, 60, STRING, 1, SIZE_MAX) \
DHCP_OPT(CLIENT_ID, 61, UINT8, 2, SIZE_MAX) \
DHCP_VNDOPT(OFP_CONTROLLER_VCONN, 1, STRING, 1, SIZE_MAX) \
DHCP_VNDOPT(OFP_PKI_URI, 2, STRING, 1, SIZE_MAX)
/* Shorthand for defining vendor options (used above). */
#define DHCP_VNDOPT(NAME, CODE, ARG, MIN, MAX) \
DHCP_OPT(NAME, (CODE) + DHCP_VENDOR_OFS, ARG, MIN, MAX)
/* DHCP option codes. */
enum {
#define DHCP_OPT(NAME, VALUE, ARGTYPE, MIN_ARGS, MAX_ARGS) \
DHCP_CODE_##NAME = VALUE,
DHCP_OPTS
#undef DHCP_OPT
};
/* The contents of a DHCP option.
*
* DHCP options can (rarely) be present but lack content. To represent such an
* option, 'n' is 0 and 'data' is non-null (but does not point to anything
* useful). */
struct dhcp_option {
size_t n; /* Number of bytes of data. */
void *data; /* Data. */
};
const char *dhcp_option_to_string(const struct dhcp_option *, int code,
struct ds *);
bool dhcp_option_equals(const struct dhcp_option *,
const struct dhcp_option *);
/* Abstracted DHCP protocol message, to make them easier to manipulate than
* through raw protocol buffers. */
struct dhcp_msg {
/* For use by calling code. */
uint8_t op; /* DHCP_BOOTREQUEST or DHCP_BOOTREPLY. */
uint32_t xid; /* Transaction ID. */
uint16_t secs; /* Since client started address acquisition. */
uint16_t flags; /* DHCP_FLAGS_*. */
uint32_t ciaddr; /* Client IP, if it has a lease for one. */
uint32_t yiaddr; /* Client ("your") IP address. */
uint32_t siaddr; /* Next server IP address. */
uint32_t giaddr; /* Relay agent IP address. */
uint8_t chaddr[ETH_ADDR_LEN]; /* Client hardware address. */
enum dhcp_msg_type type; /* DHCP_CODE_DHCP_MSG_TYPE option argument. */
struct dhcp_option options[DHCP_N_OPTIONS]; /* Indexed by option code. */
/* For direct use only by dhcp_msg_*() functions. */
uint8_t *data;
size_t data_used, data_allocated;
};
void dhcp_msg_init(struct dhcp_msg *);
void dhcp_msg_uninit(struct dhcp_msg *);
void dhcp_msg_copy(struct dhcp_msg *, const struct dhcp_msg *);
void dhcp_msg_put(struct dhcp_msg *, int code, const void *, size_t);
void dhcp_msg_put_bool(struct dhcp_msg *, int code, bool);
void dhcp_msg_put_secs(struct dhcp_msg *, int code, uint32_t);
void dhcp_msg_put_ip(struct dhcp_msg *, int code, uint32_t);
void dhcp_msg_put_string(struct dhcp_msg *, int code, const char *);
void dhcp_msg_put_uint8(struct dhcp_msg *, int code, uint8_t);
void dhcp_msg_put_uint8_array(struct dhcp_msg *, int code,
const uint8_t[], size_t n);
void dhcp_msg_put_uint16(struct dhcp_msg *, int code, uint16_t);
void dhcp_msg_put_uint16_array(struct dhcp_msg *, int code,
const uint16_t[], size_t n);
const void *dhcp_msg_get(const struct dhcp_msg *, int code, size_t offset,
size_t size);
bool dhcp_msg_get_bool(const struct dhcp_msg *, int code,
size_t offset, bool *);
bool dhcp_msg_get_secs(const struct dhcp_msg *, int code,
size_t offset, uint32_t *);
bool dhcp_msg_get_ip(const struct dhcp_msg *, int code,
size_t offset, uint32_t *);
char *dhcp_msg_get_string(const struct dhcp_msg *, int code);
bool dhcp_msg_get_uint8(const struct dhcp_msg *, int code,
size_t offset, uint8_t *);
bool dhcp_msg_get_uint16(const struct dhcp_msg *, int code,
size_t offset, uint16_t *);
const char *dhcp_msg_to_string(const struct dhcp_msg *, bool multiline,
struct ds *);
int dhcp_parse(struct dhcp_msg *, const struct ofpbuf *);
void dhcp_assemble(const struct dhcp_msg *, struct ofpbuf *);
#endif /* dhcp.h */

View File

@@ -175,10 +175,9 @@ struct netdev_class {
*
* May return -EOPNOTSUPP if a network device does not implement packet
* reception through this interface. This function may be set to null if
* it would always return -EOPNOTSUPP anyhow. (This will disable the OVS
* integrated DHCP client and OpenFlow controller discovery, and prevent
* the network device from being usefully used by the netdev-based
* "userspace datapath".) */
* it would always return -EOPNOTSUPP anyhow. (This will prevent the
* network device from being usefully used by the netdev-based "userspace
* datapath".) */
int (*recv)(struct netdev *netdev, void *buffer, size_t size);
/* Registers with the poll loop to wake up from the next call to
@@ -209,10 +208,9 @@ struct netdev_class {
*
* May return EOPNOTSUPP if a network device does not implement packet
* transmission through this interface. This function may be set to null
* if it would always return EOPNOTSUPP anyhow. (This will disable the OVS
* integrated DHCP client and OpenFlow controller discovery, and prevent
* the network device from being usefully used by the netdev-based
* "userspace datapath".) */
* if it would always return EOPNOTSUPP anyhow. (This will prevent the
* network device from being usefully used by the netdev-based "userspace
* datapath".) */
int (*send)(struct netdev *netdev, const void *buffer, size_t size);
/* Registers with the poll loop to wake up from the next call to

View File

@@ -104,16 +104,6 @@ struct rconn {
time_t creation_time;
unsigned long int total_time_connected;
/* If we can't connect to the peer, it could be for any number of reasons.
* Usually, one would assume it is because the peer is not running or
* because the network is partitioned. But it could also be because the
* network topology has changed, in which case the upper layer will need to
* reassess it (in particular, obtain a new IP address via DHCP and find
* the new location of the controller). We set this flag when we suspect
* that this could be the case. */
bool questionable_connectivity;
time_t last_questioned;
/* Throughout this file, "probe" is shorthand for "inactivity probe".
* When nothing has been received from the peer for a while, we send out
* an echo request as an inactivity probe packet. We should receive back
@@ -149,7 +139,6 @@ static void reconnect(struct rconn *);
static void report_error(struct rconn *, int error);
static void disconnect(struct rconn *, int error);
static void flush_queue(struct rconn *);
static void question_connectivity(struct rconn *);
static void copy_to_monitor(struct rconn *, const struct ofpbuf *);
static bool is_connected_state(enum state);
static bool is_admitted_msg(const struct ofpbuf *);
@@ -204,9 +193,6 @@ rconn_create(int probe_interval, int max_backoff)
rc->creation_time = time_now();
rc->total_time_connected = 0;
rc->questionable_connectivity = false;
rc->last_questioned = time_now();
rconn_set_probe_interval(rc, probe_interval);
rc->n_monitors = 0;
@@ -464,7 +450,6 @@ static void
run_IDLE(struct rconn *rc)
{
if (timed_out(rc)) {
question_connectivity(rc);
VLOG_ERR("%s: no response to inactivity probe after %u "
"seconds, disconnecting",
rc->name, elapsed_in_this_state(rc));
@@ -746,22 +731,6 @@ rconn_get_local_port(const struct rconn *rconn)
return rconn->vconn ? vconn_get_local_port(rconn->vconn) : 0;
}
/* If 'rconn' can't connect to the peer, it could be for any number of reasons.
* Usually, one would assume it is because the peer is not running or because
* the network is partitioned. But it could also be because the network
* topology has changed, in which case the upper layer will need to reassess it
* (in particular, obtain a new IP address via DHCP and find the new location
* of the controller). When this appears that this might be the case, this
* function returns true. It also clears the questionability flag and prevents
* it from being set again for some time. */
bool
rconn_is_connectivity_questionable(struct rconn *rconn)
{
bool questionable = rconn->questionable_connectivity;
rconn->questionable_connectivity = false;
return questionable;
}
/* Returns the total number of packets successfully received by the underlying
* vconn. */
unsigned int
@@ -1012,9 +981,6 @@ disconnect(struct rconn *rc, int error)
}
rc->backoff_deadline = now + rc->backoff;
state_transition(rc, S_BACKOFF);
if (now - rc->last_connected > 60) {
question_connectivity(rc);
}
} else {
rc->last_disconnected = time_now();
rconn_disconnect(rc);
@@ -1080,16 +1046,6 @@ state_transition(struct rconn *rc, enum state state)
rc->state_entered = time_now();
}
static void
question_connectivity(struct rconn *rc)
{
time_t now = time_now();
if (now - rc->last_questioned > 60) {
rc->questionable_connectivity = true;
rc->last_questioned = now;
}
}
static void
copy_to_monitor(struct rconn *rc, const struct ofpbuf *b)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2009, 2010 Nicira Networks.
* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,7 +70,6 @@ bool rconn_is_alive(const struct rconn *);
bool rconn_is_connected(const struct rconn *);
bool rconn_is_admitted(const struct rconn *);
int rconn_failure_duration(const struct rconn *);
bool rconn_is_connectivity_questionable(struct rconn *);
uint32_t rconn_get_remote_ip(const struct rconn *);
uint16_t rconn_get_remote_port(const struct rconn *);

View File

@@ -9,8 +9,6 @@ noinst_LIBRARIES += ofproto/libofproto.a
ofproto_libofproto_a_SOURCES = \
ofproto/collectors.c \
ofproto/collectors.h \
ofproto/discovery.c \
ofproto/discovery.h \
ofproto/fail-open.c \
ofproto/fail-open.h \
ofproto/in-band.c \

View File

@@ -1,243 +0,0 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* 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 "discovery.h"
#include <errno.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <net/if.h>
#include <regex.h>
#include <stdlib.h>
#include <string.h>
#include "dhcp-client.h"
#include "dhcp.h"
#include "dpif.h"
#include "netdev.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "stream-ssl.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(discovery);
struct discovery {
char *dpif_name;
char *re;
bool update_resolv_conf;
regex_t *regex;
struct dhclient *dhcp;
int n_changes;
};
static void modify_dhcp_request(struct dhcp_msg *, void *aux);
static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
int
discovery_create(const char *re, bool update_resolv_conf,
struct dpif *dpif, struct discovery **discoveryp)
{
struct discovery *d;
char local_name[IF_NAMESIZE];
int error;
d = xzalloc(sizeof *d);
d->dpif_name = xstrdup(dpif_base_name(dpif));
/* Controller regular expression. */
error = discovery_set_accept_controller_re(d, re);
if (error) {
goto error_free;
}
d->update_resolv_conf = update_resolv_conf;
/* Initialize DHCP client. */
error = dpif_port_get_name(dpif, ODPP_LOCAL,
local_name, sizeof local_name);
if (error) {
VLOG_ERR("%s: failed to query datapath local port: %s",
d->dpif_name, strerror(error));
goto error_regfree;
}
error = dhclient_create(local_name, modify_dhcp_request,
validate_dhcp_offer, d, &d->dhcp);
if (error) {
VLOG_ERR("%s: failed to initialize DHCP client: %s",
d->dpif_name, strerror(error));
goto error_regfree;
}
dhclient_set_max_timeout(d->dhcp, 3);
dhclient_init(d->dhcp, 0);
*discoveryp = d;
return 0;
error_regfree:
regfree(d->regex);
free(d->regex);
error_free:
free(d->dpif_name);
free(d);
*discoveryp = 0;
return error;
}
void
discovery_destroy(struct discovery *d)
{
if (d) {
free(d->re);
regfree(d->regex);
free(d->regex);
dhclient_destroy(d->dhcp);
free(d->dpif_name);
free(d);
}
}
bool
discovery_get_update_resolv_conf(const struct discovery *d)
{
return d->update_resolv_conf;
}
void
discovery_set_update_resolv_conf(struct discovery *d,
bool update_resolv_conf)
{
d->update_resolv_conf = update_resolv_conf;
}
const char *
discovery_get_accept_controller_re(const struct discovery *d)
{
return d->re;
}
int
discovery_set_accept_controller_re(struct discovery *d, const char *re_)
{
regex_t *regex;
int error;
char *re;
re = (!re_ ? xstrdup(stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
: re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
regex = xmalloc(sizeof *regex);
error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
if (error) {
size_t length = regerror(error, regex, NULL, 0);
char *buffer = xmalloc(length);
regerror(error, regex, buffer, length);
VLOG_WARN("%s: %s: %s", d->dpif_name, re, buffer);
free(buffer);
free(regex);
free(re);
return EINVAL;
} else {
if (d->regex) {
regfree(d->regex);
free(d->regex);
}
free(d->re);
d->regex = regex;
d->re = re;
return 0;
}
}
void
discovery_question_connectivity(struct discovery *d)
{
if (d->dhcp) {
dhclient_force_renew(d->dhcp, 15);
}
}
bool
discovery_run(struct discovery *d, char **controller_name)
{
if (!d->dhcp) {
*controller_name = NULL;
return true;
}
dhclient_run(d->dhcp);
if (!dhclient_changed(d->dhcp)) {
return false;
}
dhclient_configure_netdev(d->dhcp);
if (d->update_resolv_conf) {
dhclient_update_resolv_conf(d->dhcp);
}
if (dhclient_is_bound(d->dhcp)) {
*controller_name = dhcp_msg_get_string(dhclient_get_config(d->dhcp),
DHCP_CODE_OFP_CONTROLLER_VCONN);
VLOG_INFO("%s: discovered controller %s",
d->dpif_name, *controller_name);
d->n_changes++;
} else {
*controller_name = NULL;
if (d->n_changes) {
VLOG_INFO("%s: discovered controller no longer available",
d->dpif_name);
d->n_changes++;
}
}
return true;
}
void
discovery_wait(struct discovery *d)
{
if (d->dhcp) {
dhclient_wait(d->dhcp);
}
}
static void
modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
{
dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
}
static bool
validate_dhcp_offer(const struct dhcp_msg *msg, void *d_)
{
const struct discovery *d = d_;
char *vconn_name;
bool accept;
vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
if (!vconn_name) {
VLOG_WARN_RL(&rl, "%s: rejecting DHCP offer missing controller vconn",
d->dpif_name);
return false;
}
accept = !regexec(d->regex, vconn_name, 0, NULL, 0);
if (!accept) {
VLOG_WARN_RL(&rl, "%s: rejecting controller vconn that fails to "
"match %s", d->dpif_name, d->re);
}
free(vconn_name);
return accept;
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* 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 DISCOVERY_H
#define DISCOVERY_H 1
#include <stdbool.h>
struct dpif;
struct discovery;
struct settings;
int discovery_create(const char *accept_controller_re, bool update_resolv_conf,
struct dpif *, struct discovery **);
void discovery_destroy(struct discovery *);
bool discovery_get_update_resolv_conf(const struct discovery *);
void discovery_set_update_resolv_conf(struct discovery *,
bool update_resolv_conf);
const char *discovery_get_accept_controller_re(const struct discovery *);
int discovery_set_accept_controller_re(struct discovery *, const char *re);
void discovery_question_connectivity(struct discovery *);
bool discovery_run(struct discovery *, char **controller_name);
void discovery_wait(struct discovery *);
#endif /* discovery.h */

View File

@@ -27,7 +27,6 @@
#include "byte-order.h"
#include "classifier.h"
#include "coverage.h"
#include "discovery.h"
#include "dpif.h"
#include "dynamic-string.h"
#include "fail-open.h"
@@ -332,7 +331,6 @@ struct ofconn {
/* type == OFCONN_PRIMARY only. */
enum nx_role role; /* Role. */
struct hmap_node hmap_node; /* In struct ofproto's "controllers" map. */
struct discovery *discovery; /* Controller discovery object, if enabled. */
enum ofproto_band band; /* In-band or out-of-band? */
};
@@ -544,81 +542,47 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
}
}
static bool
is_discovery_controller(const struct ofproto_controller *c)
{
return !strcmp(c->target, "discover");
}
static bool
is_in_band_controller(const struct ofproto_controller *c)
{
return is_discovery_controller(c) || c->band == OFPROTO_IN_BAND;
}
/* Creates a new controller in 'ofproto'. Some of the settings are initially
* drawn from 'c', but update_controller() needs to be called later to finish
* the new ofconn's configuration. */
static void
add_controller(struct ofproto *ofproto, const struct ofproto_controller *c)
{
struct discovery *discovery;
char *name = ofconn_make_name(ofproto, c->target);
struct ofconn *ofconn;
if (is_discovery_controller(c)) {
int error = discovery_create(c->accept_re, c->update_resolv_conf,
ofproto->dpif, &discovery);
if (error) {
return;
}
} else {
discovery = NULL;
}
ofconn = ofconn_create(ofproto, rconn_create(5, 8), OFCONN_PRIMARY);
ofconn->pktbuf = pktbuf_create();
ofconn->miss_send_len = OFP_DEFAULT_MISS_SEND_LEN;
if (discovery) {
ofconn->discovery = discovery;
} else {
char *name = ofconn_make_name(ofproto, c->target);
rconn_connect(ofconn->rconn, c->target, name);
free(name);
}
rconn_connect(ofconn->rconn, c->target, name);
hmap_insert(&ofproto->controllers, &ofconn->hmap_node,
hash_string(c->target, 0));
free(name);
}
/* Reconfigures 'ofconn' to match 'c'. This function cannot update an ofconn's
* target or turn discovery on or off (these are done by creating new ofconns
* and deleting old ones), but it can update the rest of an ofconn's
* settings. */
* target (this is done by creating new ofconns and deleting old ones), but it
* can update the rest of an ofconn's settings. */
static void
update_controller(struct ofconn *ofconn, const struct ofproto_controller *c)
{
int probe_interval;
ofconn->band = (is_in_band_controller(c)
? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
ofconn->band = c->band;
rconn_set_max_backoff(ofconn->rconn, c->max_backoff);
probe_interval = c->probe_interval ? MAX(c->probe_interval, 5) : 0;
rconn_set_probe_interval(ofconn->rconn, probe_interval);
if (ofconn->discovery) {
discovery_set_update_resolv_conf(ofconn->discovery,
c->update_resolv_conf);
discovery_set_accept_controller_re(ofconn->discovery, c->accept_re);
}
ofconn_set_rate_limit(ofconn, c->rate_limit, c->burst_limit);
}
static const char *
ofconn_get_target(const struct ofconn *ofconn)
{
return ofconn->discovery ? "discover" : rconn_get_target(ofconn->rconn);
return rconn_get_target(ofconn->rconn);
}
static struct ofconn *
@@ -641,7 +605,6 @@ update_in_band_remotes(struct ofproto *ofproto)
const struct ofconn *ofconn;
struct sockaddr_in *addrs;
size_t max_addrs, n_addrs;
bool discovery;
size_t i;
/* Allocate enough memory for as many remotes as we could possibly have. */
@@ -650,7 +613,6 @@ update_in_band_remotes(struct ofproto *ofproto)
n_addrs = 0;
/* Add all the remotes. */
discovery = false;
HMAP_FOR_EACH (ofconn, hmap_node, &ofproto->controllers) {
struct sockaddr_in *sin = &addrs[n_addrs];
@@ -663,20 +625,13 @@ update_in_band_remotes(struct ofproto *ofproto)
sin->sin_port = rconn_get_remote_port(ofconn->rconn);
n_addrs++;
}
if (ofconn->discovery) {
discovery = true;
}
}
for (i = 0; i < ofproto->n_extra_remotes; i++) {
addrs[n_addrs++] = ofproto->extra_in_band_remotes[i];
}
/* Create or update or destroy in-band.
*
* Ordinarily we only enable in-band if there's at least one remote
* address, but discovery needs the in-band rules for DHCP to be installed
* even before we know any remote addresses. */
if (n_addrs || discovery) {
/* Create or update or destroy in-band. */
if (n_addrs) {
if (!ofproto->in_band) {
in_band_create(ofproto, ofproto->dpif, &ofproto->in_band);
}
@@ -738,7 +693,7 @@ ofproto_set_controllers(struct ofproto *p,
for (i = 0; i < n_controllers; i++) {
const struct ofproto_controller *c = &controllers[i];
if (!vconn_verify_name(c->target) || !strcmp(c->target, "discover")) {
if (!vconn_verify_name(c->target)) {
if (!find_controller_by_target(p, c->target)) {
add_controller(p, c);
}
@@ -1821,7 +1776,6 @@ ofconn_destroy(struct ofconn *ofconn)
if (ofconn->type == OFCONN_PRIMARY) {
hmap_remove(&ofconn->ofproto->controllers, &ofconn->hmap_node);
}
discovery_destroy(ofconn->discovery);
list_remove(&ofconn->node);
rconn_destroy(ofconn->rconn);
@@ -1838,23 +1792,6 @@ ofconn_run(struct ofconn *ofconn)
int iteration;
size_t i;
if (ofconn->discovery) {
char *controller_name;
if (rconn_is_connectivity_questionable(ofconn->rconn)) {
discovery_question_connectivity(ofconn->discovery);
}
if (discovery_run(ofconn->discovery, &controller_name)) {
if (controller_name) {
char *ofconn_name = ofconn_make_name(p, controller_name);
rconn_connect(ofconn->rconn, controller_name, ofconn_name);
free(ofconn_name);
free(controller_name);
} else {
rconn_disconnect(ofconn->rconn);
}
}
}
for (i = 0; i < N_SCHEDULERS; i++) {
pinsched_run(ofconn->schedulers[i], do_send_packet_in, ofconn);
}
@@ -1877,7 +1814,7 @@ ofconn_run(struct ofconn *ofconn)
}
}
if (!ofconn->discovery && !rconn_is_alive(ofconn->rconn)) {
if (!rconn_is_alive(ofconn->rconn)) {
ofconn_destroy(ofconn);
}
}
@@ -1887,9 +1824,6 @@ ofconn_wait(struct ofconn *ofconn)
{
int i;
if (ofconn->discovery) {
discovery_wait(ofconn->discovery);
}
for (i = 0; i < N_SCHEDULERS; i++) {
pinsched_wait(ofconn->schedulers[i]);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2010 Nicira Networks.
* Copyright (c) 2009, 2010, 2011 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -81,10 +81,6 @@ struct ofproto_controller {
int probe_interval; /* Max idle time before probing, in seconds. */
enum ofproto_band band; /* In-band or out-of-band? */
/* Discovery options. */
char *accept_re; /* Regexp for acceptable controllers. */
bool update_resolv_conf; /* Update /etc/resolv.conf? */
/* OpenFlow packet-in rate-limiting. */
int rate_limit; /* Max packet-in rate in packets per second. */
int burst_limit; /* Limit on accumulating packet credits. */

1
tests/.gitignore vendored
View File

@@ -9,7 +9,6 @@
/test-byte-order
/test-classifier
/test-csum
/test-dhcp-client
/test-file_name
/test-flows
/test-hash

View File

@@ -68,7 +68,6 @@ lcov_wrappers = \
tests/lcov/test-byte-order \
tests/lcov/test-classifier \
tests/lcov/test-csum \
tests/lcov/test-dhcp-client \
tests/lcov/test-file_name \
tests/lcov/test-flows \
tests/lcov/test-hash \
@@ -121,7 +120,6 @@ valgrind_wrappers = \
tests/valgrind/test-byte-order \
tests/valgrind/test-classifier \
tests/valgrind/test-csum \
tests/valgrind/test-dhcp-client \
tests/valgrind/test-file_name \
tests/valgrind/test-flows \
tests/valgrind/test-hash \
@@ -278,10 +276,6 @@ tests_test_strtok_r_SOURCES = tests/test-strtok_r.c
noinst_PROGRAMS += tests/test-type-props
tests_test_type_props_SOURCES = tests/test-type-props.c
noinst_PROGRAMS += tests/test-dhcp-client
tests_test_dhcp_client_SOURCES = tests/test-dhcp-client.c
tests_test_dhcp_client_LDADD = lib/libopenvswitch.a
noinst_PROGRAMS += tests/test-uuid
tests_test_uuid_SOURCES = tests/test-uuid.c
tests_test_uuid_LDADD = lib/libopenvswitch.a

View File

@@ -1,184 +0,0 @@
/*
* Copyright (c) 2008, 2009, 2010 Nicira Networks.
*
* 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 "dhcp-client.h"
#include <arpa/inet.h>
#include <getopt.h>
#include <stdlib.h>
#include <limits.h>
#include "command-line.h"
#include "dhcp.h"
#include "fatal-signal.h"
#include "poll-loop.h"
#include "util.h"
#include "vlog.h"
/* --request-ip: IP address to request from server. If zero, then do not
* request a specific IP address. */
static struct in_addr request_ip;
/* --vendor-class: Vendor class string to include in request. If null, no
* vendor class string is included. */
static const char *vendor_class;
/* --no-resolv-conf: Update /etc/resolv.conf to match DHCP reply? */
static bool update_resolv_conf = true;
static void parse_options(int argc, char *argv[]);
static void usage(void);
static void release(void *cli_);
static void modify_dhcp_request(struct dhcp_msg *, void *aux);
int
main(int argc, char *argv[])
{
struct dhclient *cli;
int error;
set_program_name(argv[0]);
parse_options(argc, argv);
argc -= optind;
argv += optind;
if (argc != 1) {
ovs_fatal(0, "exactly one non-option argument required; "
"use --help for help");
}
error = dhclient_create(argv[0], modify_dhcp_request, NULL, NULL, &cli);
if (error) {
ovs_fatal(error, "dhclient_create failed");
}
dhclient_init(cli, request_ip.s_addr);
fatal_signal_add_hook(release, NULL, cli, true);
for (;;) {
dhclient_run(cli);
if (dhclient_changed(cli)) {
dhclient_configure_netdev(cli);
if (update_resolv_conf) {
dhclient_update_resolv_conf(cli);
}
}
dhclient_wait(cli);
poll_block();
}
}
static void
release(void *cli_)
{
struct dhclient *cli = cli_;
dhclient_release(cli);
if (dhclient_changed(cli)) {
dhclient_configure_netdev(cli);
}
}
static void
modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
{
if (vendor_class) {
dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, vendor_class);
}
}
static void
parse_options(int argc, char *argv[])
{
enum {
OPT_REQUEST_IP = UCHAR_MAX + 1,
OPT_VENDOR_CLASS,
OPT_NO_RESOLV_CONF
};
static struct option long_options[] = {
{"request-ip", required_argument, 0, OPT_REQUEST_IP },
{"vendor-class", required_argument, 0, OPT_VENDOR_CLASS },
{"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
{"verbose", optional_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
for (;;) {
int c;
c = getopt_long(argc, argv, short_options, long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
case OPT_REQUEST_IP:
if (!inet_aton(optarg, &request_ip)) {
ovs_fatal(0,
"--request-ip argument is not a valid IP address");
}
break;
case OPT_VENDOR_CLASS:
vendor_class = optarg;
break;
case OPT_NO_RESOLV_CONF:
update_resolv_conf = false;
break;
case 'h':
usage();
case 'V':
printf("%s %s compiled "__DATE__" "__TIME__"\n",
program_name, VERSION BUILDNR);
exit(EXIT_SUCCESS);
case 'v':
vlog_set_verbosity(optarg);
break;
case '?':
exit(EXIT_FAILURE);
default:
abort();
}
}
free(short_options);
}
static void
usage(void)
{
printf("%s: standalone program for testing Open vSwitch DHCP client.\n"
"usage: %s [OPTIONS] NETDEV\n"
"where NETDEV is a network device (e.g. eth0).\n"
"\nDHCP options:\n"
" --request-ip=IP request specified IP address (default:\n"
" do not request a specific IP)\n"
" --vendor-class=STRING use STRING as vendor class; use\n"
" OpenFlow to imitate ovs-openflowd\n"
" --no-resolv-conf do not update /etc/resolv.conf\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
" -h, --help display this help message\n"
" -V, --version display version information\n");
exit(EXIT_SUCCESS);
}

View File

@@ -7,8 +7,6 @@
/ovs-cfg-mod.8
/ovs-controller
/ovs-controller.8
/ovs-discover
/ovs-discover.8
/ovs-dpctl
/ovs-dpctl.8
/ovs-ofctl

View File

@@ -1,7 +1,6 @@
bin_PROGRAMS += \
utilities/ovs-appctl \
utilities/ovs-controller \
utilities/ovs-discover \
utilities/ovs-dpctl \
utilities/ovs-ofctl \
utilities/ovs-openflowd \
@@ -18,7 +17,6 @@ noinst_SCRIPTS += utilities/ovs-pki-cgi utilities/ovs-parse-leaks
EXTRA_DIST += \
utilities/ovs-appctl.8.in \
utilities/ovs-controller.8.in \
utilities/ovs-discover.8.in \
utilities/ovs-dpctl.8.in \
utilities/ovs-ofctl.8.in \
utilities/ovs-openflowd.8.in \
@@ -40,7 +38,6 @@ EXTRA_DIST += \
DISTCLEANFILES += \
utilities/ovs-appctl.8 \
utilities/ovs-controller.8 \
utilities/ovs-discover.8 \
utilities/ovs-dpctl.8 \
utilities/ovs-ofctl.8 \
utilities/ovs-openflowd.8 \
@@ -59,7 +56,6 @@ DISTCLEANFILES += \
man_MANS += \
utilities/ovs-appctl.8 \
utilities/ovs-controller.8 \
utilities/ovs-discover.8 \
utilities/ovs-dpctl.8 \
utilities/ovs-ofctl.8 \
utilities/ovs-openflowd.8 \
@@ -77,9 +73,6 @@ utilities_ovs_appctl_LDADD = lib/libopenvswitch.a
utilities_ovs_controller_SOURCES = utilities/ovs-controller.c
utilities_ovs_controller_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
utilities_ovs_discover_SOURCES = utilities/ovs-discover.c
utilities_ovs_discover_LDADD = lib/libopenvswitch.a
utilities_ovs_dpctl_SOURCES = utilities/ovs-dpctl.c
utilities_ovs_dpctl_LDADD = lib/libopenvswitch.a

View File

@@ -168,5 +168,4 @@ white space.
.BR ovs\-vswitchd (8),
.BR ovs\-openflowd (8),
.BR ovs\-controller (8),
.BR ovs\-brcompatd (8),
.BR ovs\-discover (8).
.BR ovs\-brcompatd (8).

View File

@@ -1,118 +0,0 @@
.TH ovs\-discover 8 "May 2008" "Open vSwitch" "Open vSwitch Manual"
.ds PN ovs\-discover
.SH NAME
ovs\-discover \- controller discovery utility
.SH SYNOPSIS
.B ovs\-discover
[\fIoptions\fR] \fInetdev\fR [\fInetdev\fR...]
.SH DESCRIPTION
The \fBovs\-discover\fR program attempts to discover the location of
an OpenFlow controller on one of the network devices listed on the
command line. It repeatedly broadcasts a DHCP request with vendor
class identifier \fBOpenFlow\fR on each network device until it
receives an acceptable DHCP response. It will accept any valid DHCP
reply that has the same vendor class identifier and includes a
vendor-specific option with code 1 whose contents are a string
specifying the location of the controller in the same format used on
the \fBovs\-openflowd\fR command line (e.g. \fBssl:192.168.0.1\fR).
When \fBovs\-discover\fR receives an acceptable response, it prints
the details of the response on \fBstdout\fR. Then, by default, it
configures the network device on which the response was received with
the received IP address, netmask, and default gateway, and detaches
itself to the background.
.SH OPTIONS
.TP
\fB\-\-accept\-vconn=\fIregex\fR
With this option, only controllers whose names match POSIX extended
regular expression \fIregex\fR will be accepted. Specifying
\fBssl:.*\fR for \fIregex\fR, for example, would cause only SSL
controller connections to be accepted.
The \fIregex\fR is implicitly anchored at the beginning of the
controller location string, as if it begins with \fB^\fR.
When this option is not given, the default \fIregex\fR is
\fBtcp:.*\fR.
.TP
\fB\-\-exit\-without\-bind\fR
By default, \fBovs\-discover\fR binds the network device that receives
the first acceptable response to the IP address received over DHCP.
With this option, the configuration of the network device is not
changed at all, except to bring it up if it is initially down, and
\fBovs\-discover\fR will exit immediately after it receives an
acceptable DHCP response.
This option is mutually exclusive with \fB\-\-exit\-after\-bind\fR and
\fB\-\-no\-detach\fR.
.TP
\fB\-\-exit\-after\-bind\fR
By default, after it receives an acceptable DHCP response,
\fBovs\-discover\fR detaches itself from the foreground session and
runs in the background maintaining the DHCP lease as necessary. With
this option, \fBovs\-discover\fR will exit immediately after it
receives an acceptable DHCP response and configures the network device
with the received IP address. The address obtained via DHCP could
therefore be used past the expiration of its lease.
This option is mutually exclusive with \fB\-\-exit\-without\-bind\fR and
\fB\-\-no\-detach\fR.
.TP
\fB\-\-no\-detach\fR
By default, \fBovs\-discover\fR runs in the foreground until it obtains
an acceptable DHCP response, then it detaches itself from the
foreground session and run as a background process. This option
prevents \fBovs\-discover\fR from detaching, causing it to run in the
foreground even after it obtains a DHCP response.
This option is mutually exclusive with \fB\-\-exit\-without\-bind\fR and
\fB\-\-exit\-after\-bind\fR.
.TP
\fB\-\-pidfile\fR[\fB=\fIpidfile\fR]
Causes a file (by default, \fBovs\-discover.pid\fR) to be created indicating
the PID of the running process. If \fIpidfile\fR is not specified, or
if it does not begin with \fB/\fR, then it is created in
\fB@RUNDIR@\fR.
The \fIpidfile\fR is created when \fBovs\-discover\fR detaches, so
this this option has no effect when one of \fB\-\-exit\-without\-bind\fR,
\fB\-\-exit\-after\-bind\fR, or \fB\-\-no\-detach\fR is also given.
.TP
\fB\-\-overwrite\-pidfile\fR
By default, when \fB\-\-pidfile\fR is specified and the specified pidfile
already exists and is locked by a running process, \fBcontroller\fR refuses
to start. Specify \fB\-\-overwrite\-pidfile\fR to cause it to instead
overwrite the pidfile.
When \fB\-\-pidfile\fR is not specified, this option has no effect.
.so lib/vlog.man
.so lib/common.man
.SH BUGS
If the network devices specified on the command line have been added
to an Open vSwitch datapath with \fBovs\-dpctl add\-if\fR, then controller
discovery will fail because \fBovs\-discover\fR will not be able to
see DHCP responses, even though tools such as \fBtcpdump\fR(8) and
\fBwireshark\fR(1) can see them on the wire. This is because of the
structure of the Linux kernel networking stack, which hands packets
first to programs that listen for all arriving packets, then to
Open vSwitch, then to programs that listen for a specific kind of packet.
Open vSwitch consumes all the packets handed to it, so tools like
\fBtcpdump\fR that look at all packets will see packets arriving on
Open vSwitch interfaces, but \fRovs\-discover\fR, which listens only for
arriving IP packets, will not.
.SH "SEE ALSO"
.BR ovs\-openflowd (8),
.BR ovs\-pki (8)

View File

@@ -1,403 +0,0 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
*
* 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 <getopt.h>
#include <limits.h>
#include <regex.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include "command-line.h"
#include "daemon.h"
#include "dhcp-client.h"
#include "dhcp.h"
#include "dirs.h"
#include "dynamic-string.h"
#include "fatal-signal.h"
#include "netdev.h"
#include "poll-loop.h"
#include "timeval.h"
#include "unixctl.h"
#include "util.h"
#include "vlog.h"
VLOG_DEFINE_THIS_MODULE(ovs_discover);
struct iface {
const char *name;
struct dhclient *dhcp;
};
/* The interfaces that we serve. */
static struct iface *ifaces;
static int n_ifaces;
/* --accept-vconn: Regular expression specifying the class of controller vconns
* that we will accept during autodiscovery. */
static const char *accept_controller_re = "tcp:.*";
static regex_t accept_controller_regex;
/* --exit-without-bind: Exit after discovering the controller, without binding
* the network device to an IP address? */
static bool exit_without_bind;
/* --exit-after-bind: Exit after discovering the controller, after binding the
* network device to an IP address? */
static bool exit_after_bind;
static bool iface_init(struct iface *, const char *netdev_name);
static void release_ifaces(void *aux OVS_UNUSED);
static void parse_options(int argc, char *argv[]);
static void usage(void) NO_RETURN;
static void modify_dhcp_request(struct dhcp_msg *, void *aux);
static bool validate_dhcp_offer(const struct dhcp_msg *, void *aux);
int
main(int argc, char *argv[])
{
struct unixctl_server *unixctl;
int retval;
int i;
proctitle_init(argc, argv);
set_program_name(argv[0]);
parse_options(argc, argv);
argc -= optind;
argv += optind;
if (argc < 1) {
ovs_fatal(0, "need at least one non-option argument; "
"use --help for usage");
}
ifaces = xmalloc(argc * sizeof *ifaces);
n_ifaces = 0;
for (i = 0; i < argc; i++) {
if (iface_init(&ifaces[n_ifaces], argv[i])) {
n_ifaces++;
}
}
if (!n_ifaces) {
ovs_fatal(0, "failed to initialize any DHCP clients");
}
for (i = 0; i < n_ifaces; i++) {
struct iface *iface = &ifaces[i];
dhclient_init(iface->dhcp, 0);
}
fatal_signal_add_hook(release_ifaces, NULL, NULL, true);
retval = regcomp(&accept_controller_regex, accept_controller_re,
REG_NOSUB | REG_EXTENDED);
if (retval) {
size_t length = regerror(retval, &accept_controller_regex, NULL, 0);
char *buffer = xmalloc(length);
regerror(retval, &accept_controller_regex, buffer, length);
ovs_fatal(0, "%s: %s", accept_controller_re, buffer);
}
retval = unixctl_server_create(NULL, &unixctl);
if (retval) {
exit(EXIT_FAILURE);
}
die_if_already_running();
signal(SIGPIPE, SIG_IGN);
for (;;) {
for (i = 0; i < n_ifaces; i++) {
struct iface *iface = &ifaces[i];
dhclient_run(iface->dhcp);
if (dhclient_changed(iface->dhcp)) {
bool is_bound = dhclient_is_bound(iface->dhcp);
int j;
/* Configure network device. */
if (!exit_without_bind) {
dhclient_configure_netdev(iface->dhcp);
dhclient_update_resolv_conf(iface->dhcp);
}
if (is_bound) {
static bool detached = false;
struct ds ds;
/* Disable timeout, since discovery was successful. */
time_alarm(0);
/* Print discovered parameters. */
ds_init(&ds);
dhcp_msg_to_string(dhclient_get_config(iface->dhcp),
true, &ds);
fputs(ds_cstr(&ds), stdout);
putchar('\n');
fflush(stdout);
ds_destroy(&ds);
/* Exit if the user requested it. */
if (exit_without_bind) {
VLOG_DBG("exiting because of successful binding on %s "
"and --exit-without-bind specified",
iface->name);
exit(0);
}
if (exit_after_bind) {
VLOG_DBG("exiting because of successful binding on %s "
"and --exit-after-bind specified",
iface->name);
exit(0);
}
/* Detach into background, if we haven't already. */
if (!detached) {
detached = true;
daemonize();
}
}
/* We only want an address on a single one of our interfaces.
* So: if we have an address on this interface, stop looking
* for one on the others; if we don't have an address on this
* interface, start looking everywhere. */
for (j = 0; j < n_ifaces; j++) {
struct iface *if2 = &ifaces[j];
if (iface != if2) {
if (is_bound) {
dhclient_release(if2->dhcp);
} else {
dhclient_init(if2->dhcp, 0);
}
}
}
}
}
unixctl_server_run(unixctl);
for (i = 0; i < n_ifaces; i++) {
struct iface *iface = &ifaces[i];
dhclient_wait(iface->dhcp);
}
unixctl_server_wait(unixctl);
poll_block();
}
return 0;
}
static bool
iface_init(struct iface *iface, const char *netdev_name)
{
int retval;
iface->name = netdev_name;
iface->dhcp = NULL;
if (exit_after_bind) {
/* Bring this interface up permanently, so that the bound address
* persists past program termination. */
struct netdev *netdev;
retval = netdev_open_default(iface->name, &netdev);
if (retval) {
ovs_error(retval, "Could not open %s device", iface->name);
return false;
}
retval = netdev_turn_flags_on(netdev, NETDEV_UP, true);
if (retval) {
ovs_error(retval, "Could not bring %s device up", iface->name);
return false;
}
netdev_close(netdev);
}
retval = dhclient_create(iface->name, modify_dhcp_request,
validate_dhcp_offer, NULL, &iface->dhcp);
if (retval) {
ovs_error(retval, "%s: failed to initialize DHCP client", iface->name);
return false;
}
return true;
}
static void
release_ifaces(void *aux OVS_UNUSED)
{
int i;
for (i = 0; i < n_ifaces; i++) {
struct dhclient *dhcp = ifaces[i].dhcp;
dhclient_release(dhcp);
if (dhclient_changed(dhcp)) {
dhclient_configure_netdev(dhcp);
}
}
}
static void
modify_dhcp_request(struct dhcp_msg *msg, void *aux OVS_UNUSED)
{
dhcp_msg_put_string(msg, DHCP_CODE_VENDOR_CLASS, "OpenFlow");
}
static bool
validate_dhcp_offer(const struct dhcp_msg *msg, void *aux OVS_UNUSED)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(60, 60);
char *vconn_name;
bool accept;
vconn_name = dhcp_msg_get_string(msg, DHCP_CODE_OFP_CONTROLLER_VCONN);
if (!vconn_name) {
VLOG_WARN_RL(&rl, "rejecting DHCP offer missing controller vconn");
return false;
}
accept = !regexec(&accept_controller_regex, vconn_name, 0, NULL, 0);
free(vconn_name);
return accept;
}
static void
parse_options(int argc, char *argv[])
{
enum {
OPT_ACCEPT_VCONN = UCHAR_MAX + 1,
OPT_EXIT_WITHOUT_BIND,
OPT_EXIT_AFTER_BIND,
OPT_NO_DETACH,
VLOG_OPTION_ENUMS,
DAEMON_OPTION_ENUMS
};
static struct option long_options[] = {
{"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
{"exit-without-bind", no_argument, 0, OPT_EXIT_WITHOUT_BIND},
{"exit-after-bind", no_argument, 0, OPT_EXIT_AFTER_BIND},
{"no-detach", no_argument, 0, OPT_NO_DETACH},
{"timeout", required_argument, 0, 't'},
{"pidfile", optional_argument, 0, OPT_PIDFILE},
{"overwrite-pidfile", no_argument, 0, OPT_OVERWRITE_PIDFILE},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'V'},
VLOG_LONG_OPTIONS,
{0, 0, 0, 0},
};
char *short_options = long_options_to_short_options(long_options);
bool detach_after_bind = true;
for (;;) {
unsigned long int timeout;
int c;
c = getopt_long(argc, argv, short_options, long_options, NULL);
if (c == -1) {
break;
}
switch (c) {
case OPT_ACCEPT_VCONN:
accept_controller_re = (optarg[0] == '^'
? optarg
: xasprintf("^%s", optarg));
break;
case OPT_EXIT_WITHOUT_BIND:
exit_without_bind = true;
break;
case OPT_EXIT_AFTER_BIND:
exit_after_bind = true;
break;
case OPT_NO_DETACH:
detach_after_bind = false;
break;
case OPT_PIDFILE:
set_pidfile(optarg);
break;
case OPT_OVERWRITE_PIDFILE:
ignore_existing_pidfile();
break;
case 't':
timeout = strtoul(optarg, NULL, 10);
if (timeout <= 0) {
ovs_fatal(0, "value %s on -t or --timeout is not at least 1",
optarg);
} else {
time_alarm(timeout);
}
signal(SIGALRM, SIG_DFL);
break;
case 'h':
usage();
case 'V':
OVS_PRINT_VERSION(0, 0);
exit(EXIT_SUCCESS);
VLOG_OPTION_HANDLERS
case '?':
exit(EXIT_FAILURE);
default:
abort();
}
}
free(short_options);
if ((exit_without_bind + exit_after_bind + !detach_after_bind) > 1) {
ovs_fatal(0, "--exit-without-bind, --exit-after-bind, and --no-detach "
"are mutually exclusive");
}
if (detach_after_bind) {
set_detach();
}
}
static void
usage(void)
{
printf("%s: a tool for discovering OpenFlow controllers.\n"
"usage: %s [OPTIONS] NETDEV [NETDEV...]\n"
"where each NETDEV is a network device on which to perform\n"
"controller discovery.\n"
"\nOrdinarily, ovs-discover runs in the foreground until it\n"
"obtains an IP address and discovers an OpenFlow controller via\n"
"DHCP, then it prints information about the controller to stdout\n"
"and detaches to the background to maintain the IP address lease.\n"
"\nNetworking options:\n"
" --accept-vconn=REGEX accept matching discovered controllers\n"
" --exit-without-bind exit after discovery, without binding\n"
" --exit-after-bind exit after discovery, after binding\n"
" --no-detach do not detach after discovery\n",
program_name, program_name);
vlog_usage();
printf("\nOther options:\n"
" -t, --timeout=SECS give up discovery after SECS seconds\n"
" --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n"
" --overwrite-pidfile with --pidfile, start even if already "
"running\n"
" -h, --help display this help message\n"
" -V, --version display version information\n",
ovs_rundir(), program_name);
exit(EXIT_SUCCESS);
}

View File

@@ -9,7 +9,7 @@ ovs\-openflowd \- OpenFlow switch implementation
.
.SH SYNOPSIS
.B ovs\-openflowd
[\fIoptions\fR] \fIdatapath\fR [\fIcontroller\fR\&...]
[\fIoptions\fR] \fIdatapath\fR \fIcontroller\fR\&...
.
.SH DESCRIPTION
The \fBovs\-openflowd\fR program implements an OpenFlow switch using a
@@ -46,9 +46,6 @@ switch, so more than one controller should be specified only if the
controllers are themselves designed to coordinate with each other.
(The Nicira-defined \fBNXT_ROLE\fR OpenFlow vendor extension may be
useful for this.)
.PP
If no \fIcontroller\fR is specified, \fBovs\-openflowd\fR attempts to
discover the location of a controller automatically (see below).
.
.SS "Contacting Controllers"
The OpenFlow switch must be able to contact the OpenFlow controllers
@@ -75,82 +72,8 @@ independent networks.
.IP
In-band control is the default for \fBovs\-openflowd\fR, so no special
command-line option is required.
.IP
With in-band control, the location of the controller can be configured
manually or discovered automatically:
.
.RS
.IP "controller discovery"
To make \fBovs\-openflowd\fR discover the location of the controller
automatically, do not specify a controller on the \fBovs\-openflowd\fR
command line.
.IP
In this mode, \fBovs\-openflowd\fR will broadcast a DHCP request with vendor
class identifier \fBOpenFlow\fR across the network devices added to
the datapath with \fBovs\-dpctl add\-if\fR. It will accept any valid DHCP
reply that has the same vendor class identifier and includes a
vendor-specific option with code 1 whose contents are a string
specifying the location of the controller in the same format used on
the \fBovs\-openflowd\fR command line (e.g. \fBssl:192.168.0.1\fR).
.IP
The DHCP reply may also, optionally, include a vendor-specific option
with code 2 whose contents are a string specifying the URI to the base
of the OpenFlow PKI (e.g. \fBhttp://192.168.0.1/openflow/pki\fR).
This URI is used only for bootstrapping the OpenFlow PKI at initial
switch setup; \fBovs\-openflowd\fR does not use it at all.
.IP
The following ISC DHCP server configuration file assigns the IP
address range 192.168.0.20 through 192.168.0.30 to OpenFlow switches
that follow the switch protocol and addresses 192.168.0.1 through
192.168.0.10 to all other DHCP clients:
.IP
default\-lease\-time 600;
.br
max\-lease\-time 7200;
.br
option space openflow;
.br
option openflow.controller\-vconn code 1 = text;
.br
option openflow.pki\-uri code 2 = text;
.br
class "OpenFlow" {
.br
match if option vendor\-class\-identifier = "OpenFlow";
.br
vendor\-option\-space openflow;
.br
option openflow.controller\-vconn "tcp:192.168.0.10";
.br
option openflow.pki\-uri "http://192.168.0.10/openflow/pki";
.br
option vendor\-class\-identifier "OpenFlow";
.br
}
.br
subnet 192.168.0.0 netmask 255.255.255.0 {
.br
pool {
.br
allow members of "OpenFlow";
.br
range 192.168.0.20 192.168.0.30;
.br
}
.br
pool {
.br
deny members of "OpenFlow";
.br
range 192.168.0.1 192.168.0.10;
.br
}
.br
}
.br
.
.IP "manual configuration"
To configure in-band control manually, specify the location of the
Specify the location of the
controller on the \fBovs\-openflowd\fR command line as the \fIcontroller\fR
argument. You must also configure the network device for the OpenFlow
``local port'' to allow \fBovs\-openflowd\fR to connect to that controller.
@@ -216,44 +139,6 @@ Set the description of the datapath to \fIdesc\fR, which may contain up to
purposes and is not guaranteed to be unique and should not be used as
the primary identifier of the datapath.
.
.SS "Controller Discovery Options"
.TP
\fB\-\-accept\-vconn=\fIregex\fR
When \fBovs\-openflowd\fR performs controller discovery (see \fBContacting
the Controller\fR, above, for more information about controller
discovery), it validates the controller location obtained via DHCP
with a POSIX extended regular expression. Only controllers whose
names match the regular expression will be accepted.
.IP
The default regular expression is \fBssl:.*\fR (meaning that only SSL
controller connections will be accepted) when any of the SSL
configuration options \fB\-\-private\-key\fR, \fB\-\-certificate\fR, or
\fB\-\-ca\-cert\fR is specified. The default is \fB^tcp:.*\fR otherwise
(meaning that only TCP controller connections will be accepted).
.IP
The \fIregex\fR is implicitly anchored at the beginning of the
controller location string, as if it begins with \fB^\fR.
.IP
When controller discovery is not performed, this option has no effect.
.
.TP
\fB\-\-no\-resolv\-conf\fR
When \fBovs\-openflowd\fR performs controller discovery (see \fBContacting
the Controller\fR, above, for more information about controller
discovery), by default it overwrites the system's
\fB/etc/resolv.conf\fR with domain information and DNS servers
obtained via DHCP. If the location of the controller is specified
using a hostname, rather than an IP address, and the network's DNS
servers ever change, this behavior is essential. But because it also
interferes with any administrator or process that manages
\fB/etc/resolv.conf\fR, when this option is specified, \fBovs\-openflowd\fR
will not modify \fB/etc/resolv.conf\fR.
.IP
\fBovs\-openflowd\fR will only modify \fBresolv.conf\fR if the DHCP response
that it receives specifies one or more DNS servers.
.IP
When controller discovery is not performed, this option has no effect.
.
.SS "Networking Options"
.TP
\fB\-\-datapath\-id=\fIdpid\fR
@@ -455,7 +340,6 @@ Causes \fBovs\-openflowd\fR to gracefully terminate.
.
.BR ovs\-appctl (8),
.BR ovs\-controller (8),
.BR ovs\-discover (8),
.BR ovs\-dpctl (8),
.BR ovs\-ofctl (8),
.BR ovs\-pki (8)

View File

@@ -216,8 +216,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
OPT_SW_DESC,
OPT_SERIAL_DESC,
OPT_DP_DESC,
OPT_ACCEPT_VCONN,
OPT_NO_RESOLV_CONF,
OPT_BR_NAME,
OPT_FAIL_MODE,
OPT_INACTIVITY_PROBE,
@@ -244,8 +242,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
{"sw-desc", required_argument, 0, OPT_SW_DESC},
{"serial-desc", required_argument, 0, OPT_SERIAL_DESC},
{"dp-desc", required_argument, 0, OPT_DP_DESC},
{"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
{"no-resolv-conf", no_argument, 0, OPT_NO_RESOLV_CONF},
{"config", required_argument, 0, 'F'},
{"br-name", required_argument, 0, OPT_BR_NAME},
{"fail", required_argument, 0, OPT_FAIL_MODE},
@@ -284,8 +280,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
controller_opts.max_backoff = 8;
controller_opts.probe_interval = 5;
controller_opts.band = OFPROTO_IN_BAND;
controller_opts.accept_re = NULL;
controller_opts.update_resolv_conf = true;
controller_opts.rate_limit = 0;
controller_opts.burst_limit = 0;
s->unixctl_path = NULL;
@@ -337,14 +331,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
s->dp_desc = optarg;
break;
case OPT_ACCEPT_VCONN:
controller_opts.accept_re = optarg;
break;
case OPT_NO_RESOLV_CONF:
controller_opts.update_resolv_conf = false;
break;
case OPT_FAIL_MODE:
if (!strcmp(optarg, "open") || !strcmp(optarg, "standalone")) {
s->fail_mode = OFPROTO_FAIL_STANDALONE;
@@ -467,17 +453,11 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
argc -= optind;
argv += optind;
if (argc < 1) {
ovs_fatal(0, "need at least one non-option arguments; "
if (argc < 2) {
ovs_fatal(0, "need at least two non-option arguments; "
"use --help for usage");
}
/* Set accept_controller_regex. */
if (!controller_opts.accept_re) {
controller_opts.accept_re
= stream_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*";
}
/* Rate limiting. */
if (controller_opts.rate_limit && controller_opts.rate_limit < 100) {
VLOG_WARN("Rate limit set to unusually low value %d",
@@ -500,9 +480,6 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
svec_add(&controllers, argv[i]);
}
}
if (argc < 2) {
svec_add(&controllers, "discover");
}
/* Set up controllers. */
s->n_controllers = controllers.n;
@@ -511,27 +488,16 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
s->controllers[i] = controller_opts;
s->controllers[i].target = controllers.names[i];
}
/* Sanity check. */
if (controller_opts.band == OFPROTO_OUT_OF_BAND) {
for (i = 0; i < s->n_controllers; i++) {
if (!strcmp(s->controllers[i].target, "discover")) {
ovs_fatal(0, "Cannot perform discovery with out-of-band "
"control");
}
}
}
}
static void
usage(void)
{
printf("%s: an OpenFlow switch implementation.\n"
"usage: %s [OPTIONS] [TYPE@]DATAPATH [CONTROLLER...]\n"
"usage: %s [OPTIONS] [TYPE@]DATAPATH CONTROLLER...\n"
"where DATAPATH is a local datapath (e.g. \"dp0\")\n"
"optionally with an explicit TYPE (default: \"system\").\n"
"Each CONTROLLER is an active OpenFlow connection method. If\n"
"none is given, ovs-openflowd performs controller discovery.\n",
"Each CONTROLLER is an active OpenFlow connection method.\n",
program_name, program_name);
vconn_usage(true, true, true);
printf("\nOpenFlow options:\n"
@@ -542,9 +508,6 @@ usage(void)
" --sw-desc=SW Identify software as SW\n"
" --serial-desc=SERIAL Identify serial number as SERIAL\n"
" --dp-desc=DP_DESC Identify dp description as DP_DESC\n"
"\nController discovery options:\n"
" --accept-vconn=REGEX accept matching discovered controllers\n"
" --no-resolv-conf do not update /etc/resolv.conf\n"
"\nNetworking options:\n"
" --fail=open|closed when controller connection fails:\n"
" closed: drop all packets\n"

View File

@@ -1956,8 +1956,6 @@ bridge_ofproto_controller_for_mgmt(const struct bridge *br,
oc->max_backoff = 0;
oc->probe_interval = 60;
oc->band = OFPROTO_OUT_OF_BAND;
oc->accept_re = NULL;
oc->update_resolv_conf = false;
oc->rate_limit = 0;
oc->burst_limit = 0;
}
@@ -1972,8 +1970,6 @@ bridge_ofproto_controller_from_ovsrec(const struct ovsrec_controller *c,
oc->probe_interval = c->inactivity_probe ? *c->inactivity_probe / 1000 : 5;
oc->band = (!c->connection_mode || !strcmp(c->connection_mode, "in-band")
? OFPROTO_IN_BAND : OFPROTO_OUT_OF_BAND);
oc->accept_re = c->discover_accept_regex;
oc->update_resolv_conf = c->discover_update_resolv_conf;
oc->rate_limit = c->controller_rate_limit ? *c->controller_rate_limit : 0;
oc->burst_limit = (c->controller_burst_limit
? *c->controller_burst_limit : 0);
@@ -1991,11 +1987,6 @@ bridge_configure_local_iface_netdev(struct bridge *br,
struct iface *local_iface;
struct in_addr ip;
/* Controller discovery does its own TCP/IP configuration later. */
if (strcmp(c->target, "discover")) {
return;
}
/* If there's no local interface or no IP address, give up. */
local_iface = bridge_get_local_iface(br);
if (!local_iface || !c->local_ip || !inet_aton(c->local_ip, &ip)) {

View File

@@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
"version": "2.1.0",
"cksum": "1990266641 15714",
"version": "3.0.0",
"cksum": "705848946 15525",
"tables": {
"Open_vSwitch": {
"columns": {
@@ -362,10 +362,6 @@
"min": 0, "max": 1}},
"inactivity_probe": {
"type": {"key": "integer", "min": 0, "max": 1}},
"discover_accept_regex": {
"type": {"key": "string", "min": 0, "max": 1}},
"discover_update_resolv_conf": {
"type": {"key": "boolean", "min": 0, "max": 1}},
"connection_mode": {
"type": {"key": {"type": "string",
"enum": ["set", ["in-band", "out-of-band"]]},

View File

@@ -1692,23 +1692,6 @@
<dd>The specified TCP <var>port</var> (default: 6633) on the host at
the given <var>ip</var>, which must be expressed as an IP address
(not a DNS name).</dd>
<dt><code>discover</code></dt>
<dd>
<p>Enables controller discovery.</p>
<p>In controller discovery mode, Open vSwitch broadcasts a DHCP
request with vendor class identifier <code>OpenFlow</code> across
all of the bridge's network devices. It will accept any valid
DHCP reply that has the same vendor class identifier and includes
a vendor-specific option with code 1 whose contents are a string
specifying the location of the controller in the same format as
<ref column="target"/>.</p>
<p>The DHCP reply may also, optionally, include a vendor-specific
option with code 2 whose contents are a string specifying the URI
to the base of the OpenFlow PKI
(e.g. <code>http://192.168.0.1/openflow/pki</code>). This URI is
used only for bootstrapping the OpenFlow PKI at initial switch
setup; <code>ovs-vswitchd</code> does not use it at all.</p>
</dd>
</dl>
<p>
The following connection methods are currently supported for service
@@ -1768,10 +1751,7 @@
</dd>
</dl>
<p>If not specified, the default is implementation-specific. If
<ref column="target"/> is <code>discover</code>, the connection mode
is always treated as <code>in-band</code> regardless of the actual
setting.</p>
<p>If not specified, the default is implementation-specific.</p>
</column>
</group>
@@ -1821,33 +1801,9 @@
</column>
</group>
<group title="Additional Discovery Configuration">
<p>These values are considered only when <ref column="target"/>
is <code>discover</code>.</p>
<column name="discover_accept_regex">
A POSIX
extended regular expression against which the discovered controller
location is validated. The regular expression is implicitly
anchored at the beginning of the controller location string, as
if it begins with <code>^</code>. If not specified, the default
is implementation-specific.
</column>
<column name="discover_update_resolv_conf">
Whether to update <code>/etc/resolv.conf</code> when the
controller is discovered. If not specified, the default
is implementation-specific. Open vSwitch will only modify
<code>/etc/resolv.conf</code> if the DHCP response that it receives
specifies one or more DNS servers.
</column>
</group>
<group title="Additional In-Band Configuration">
<p>These values are considered only in in-band control mode (see
<ref column="connection_mode"/>) and only when <ref column="target"/>
is not <code>discover</code>. (For controller discovery, the network
configuration obtained via DHCP is used instead.)</p>
<ref column="connection_mode"/>).</p>
<p>When multiple controllers are configured on a single bridge, there
should be only one set of unique values in these columns. If different

View File

@@ -116,11 +116,9 @@ install xenserver/uuid.py $RPM_BUILD_ROOT/usr/share/openvswitch/python
# Get rid of stuff we don't want to make RPM happy.
rm \
$RPM_BUILD_ROOT/usr/bin/ovs-controller \
$RPM_BUILD_ROOT/usr/bin/ovs-discover \
$RPM_BUILD_ROOT/usr/bin/ovs-openflowd \
$RPM_BUILD_ROOT/usr/bin/ovs-pki \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-controller.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-discover.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-openflowd.8 \
$RPM_BUILD_ROOT/usr/share/man/man8/ovs-pki.8