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:
@@ -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
|
||||
----------
|
||||
|
8
debian/openvswitch-controller.README.Debian
vendored
8
debian/openvswitch-controller.README.Debian
vendored
@@ -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
|
||||
|
1
debian/openvswitch-switch.install
vendored
1
debian/openvswitch-switch.install
vendored
@@ -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
|
||||
|
1
debian/openvswitch-switch.manpages
vendored
1
debian/openvswitch-switch.manpages
vendored
@@ -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
|
||||
|
@@ -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 \
|
||||
|
1105
lib/dhcp-client.c
1105
lib/dhcp-client.c
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
824
lib/dhcp.c
824
lib/dhcp.c
@@ -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);
|
||||
}
|
||||
|
220
lib/dhcp.h
220
lib/dhcp.h
@@ -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 */
|
||||
|
@@ -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
|
||||
|
44
lib/rconn.c
44
lib/rconn.c
@@ -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)
|
||||
{
|
||||
|
@@ -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 *);
|
||||
|
@@ -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 \
|
||||
|
@@ -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;
|
||||
}
|
@@ -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 */
|
@@ -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]);
|
||||
}
|
||||
|
@@ -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
1
tests/.gitignore
vendored
@@ -9,7 +9,6 @@
|
||||
/test-byte-order
|
||||
/test-classifier
|
||||
/test-csum
|
||||
/test-dhcp-client
|
||||
/test-file_name
|
||||
/test-flows
|
||||
/test-hash
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
2
utilities/.gitignore
vendored
2
utilities/.gitignore
vendored
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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).
|
||||
|
@@ -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)
|
@@ -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);
|
||||
}
|
@@ -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)
|
||||
|
@@ -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"
|
||||
|
@@ -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)) {
|
||||
|
@@ -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"]]},
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
||||
|
Reference in New Issue
Block a user