projects
/
openvswitch
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
vswitchd: Treat gratuitous ARP requests like gratuitous ARP replies.
[openvswitch]
/
vswitchd
/
bridge.c
diff --git
a/vswitchd/bridge.c
b/vswitchd/bridge.c
index 24db5b5e6fe7b49e96c4ee66389c0e97968f8dfe..61813bb4cb41e33b84f0c704d25ed3dd0eeb5038 100644
(file)
--- a/
vswitchd/bridge.c
+++ b/
vswitchd/bridge.c
@@
-20,6
+20,7
@@
#include <arpa/inet.h>
#include <ctype.h>
#include <inttypes.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <inttypes.h>
+#include <sys/socket.h>
#include <net/if.h>
#include <openflow/openflow.h>
#include <signal.h>
#include <net/if.h>
#include <openflow/openflow.h>
#include <signal.h>
@@
-122,7
+123,8
@@
struct port {
struct bridge *bridge;
size_t port_idx;
int vlan; /* -1=trunk port, else a 12-bit VLAN ID. */
struct bridge *bridge;
size_t port_idx;
int vlan; /* -1=trunk port, else a 12-bit VLAN ID. */
- unsigned long *trunks; /* Bitmap of trunked VLANs, if 'vlan' == -1. */
+ unsigned long *trunks; /* Bitmap of trunked VLANs, if 'vlan' == -1.
+ * NULL if all VLANs are trunked. */
char *name;
/* An ordinary bridge port has 1 interface.
char *name;
/* An ordinary bridge port has 1 interface.
@@
-177,6
+179,7
@@
struct bridge {
struct port **ports;
size_t n_ports, allocated_ports;
struct shash iface_by_name; /* "struct iface"s indexed by name. */
struct port **ports;
size_t n_ports, allocated_ports;
struct shash iface_by_name; /* "struct iface"s indexed by name. */
+ struct shash port_by_name; /* "struct port"s indexed by name. */
/* Bonding. */
bool has_bonded_ports;
/* Bonding. */
bool has_bonded_ports;
@@
-1208,6
+1211,7
@@
bridge_create(const struct ovsrec_bridge *br_cfg)
port_array_init(&br->ifaces);
port_array_init(&br->ifaces);
+ shash_init(&br->port_by_name);
shash_init(&br->iface_by_name);
br->flush = false;
shash_init(&br->iface_by_name);
br->flush = false;
@@
-1238,6
+1242,7
@@
bridge_destroy(struct bridge *br)
ofproto_destroy(br->ofproto);
mac_learning_destroy(br->ml);
port_array_destroy(&br->ifaces);
ofproto_destroy(br->ofproto);
mac_learning_destroy(br->ml);
port_array_destroy(&br->ifaces);
+ shash_destroy(&br->port_by_name);
shash_destroy(&br->iface_by_name);
free(br->ports);
free(br->name);
shash_destroy(&br->iface_by_name);
free(br->ports);
free(br->name);
@@
-1982,11
+1987,11
@@
bond_wait(struct bridge *br)
for (j = 0; j < port->n_ifaces; j++) {
struct iface *iface = port->ifaces[j];
if (iface->delay_expires != LLONG_MAX) {
for (j = 0; j < port->n_ifaces; j++) {
struct iface *iface = port->ifaces[j];
if (iface->delay_expires != LLONG_MAX) {
- poll_timer_wait
(iface->delay_expires - time_msec()
);
+ poll_timer_wait
_until(iface->delay_expires
);
}
}
if (port->bond_fake_iface) {
}
}
if (port->bond_fake_iface) {
- poll_timer_wait
(port->bond_next_fake_iface_update - time_msec()
);
+ poll_timer_wait
_until(port->bond_next_fake_iface_update
);
}
}
}
}
}
}
@@
-2070,7
+2075,8
@@
dst_is_duplicate(const struct dst *dsts, size_t n_dsts,
static bool
port_trunks_vlan(const struct port *port, uint16_t vlan)
{
static bool
port_trunks_vlan(const struct port *port, uint16_t vlan)
{
- return port->vlan < 0 && bitmap_is_set(port->trunks, vlan);
+ return (port->vlan < 0
+ && (!port->trunks || bitmap_is_set(port->trunks, vlan)));
}
static bool
}
static bool
@@
-2263,12
+2269,17
@@
update_learning_table(struct bridge *br, const flow_t *flow, int vlan,
}
}
}
}
+/* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
+ * migration. Older Citrix-patched Linux DomU used gratuitous ARP replies to
+ * indicate this; newer upstream kernels use gratuitous ARP requests. */
static bool
static bool
-is_
bcast_arp_reply
(const flow_t *flow)
+is_
gratuitous_arp
(const flow_t *flow)
{
return (flow->dl_type == htons(ETH_TYPE_ARP)
{
return (flow->dl_type == htons(ETH_TYPE_ARP)
- && flow->nw_proto == ARP_OP_REPLY
- && eth_addr_is_broadcast(flow->dl_dst));
+ && eth_addr_is_broadcast(flow->dl_dst)
+ && (flow->nw_proto == ARP_OP_REPLY
+ || (flow->nw_proto == ARP_OP_REQUEST
+ && flow->nw_src == flow->nw_dst)));
}
/* Determines whether packets in 'flow' within 'br' should be forwarded or
}
/* Determines whether packets in 'flow' within 'br' should be forwarded or
@@
-2360,11
+2371,11
@@
is_admissible(struct bridge *br, const flow_t *flow, bool have_packet,
/* Drop all packets for which we have learned a different input
* port, because we probably sent the packet on one slave and got
/* Drop all packets for which we have learned a different input
* port, because we probably sent the packet on one slave and got
- * it back on the other.
Broadcast ARP replie
s are an exception
+ * it back on the other.
Gratuitous ARP packet
s are an exception
* to this rule: the host has moved to another switch. */
src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
if (src_idx != -1 && src_idx != in_port->port_idx &&
* to this rule: the host has moved to another switch. */
src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
if (src_idx != -1 && src_idx != in_port->port_idx &&
- !is_
bcast_arp_reply
(flow)) {
+ !is_
gratuitous_arp
(flow)) {
return false;
}
}
return false;
}
}
@@
-3226,6
+3237,7
@@
port_create(struct bridge *br, const char *name)
sizeof *br->ports);
}
br->ports[br->n_ports++] = port;
sizeof *br->ports);
}
br->ports[br->n_ports++] = port;
+ shash_add_assert(&br->port_by_name, port->name, port);
VLOG_INFO("created port %s on bridge %s", port->name, br->name);
bridge_flush(br);
VLOG_INFO("created port %s on bridge %s", port->name, br->name);
bridge_flush(br);
@@
-3350,7
+3362,7
@@
port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
/* Get trunked VLANs. */
trunks = NULL;
/* Get trunked VLANs. */
trunks = NULL;
- if (vlan < 0) {
+ if (vlan < 0
&& cfg->n_trunks
) {
size_t n_errors;
size_t i;
size_t n_errors;
size_t i;
@@
-3369,17
+3381,14
@@
port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
port->name, cfg->n_trunks);
}
if (n_errors == cfg->n_trunks) {
port->name, cfg->n_trunks);
}
if (n_errors == cfg->n_trunks) {
- if (n_errors) {
- VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
- port->name);
- }
- bitmap_set_multiple(trunks, 0, 4096, 1);
- }
- } else {
- if (cfg->n_trunks) {
- VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+ VLOG_ERR("port %s: no valid trunks, trunking all VLANs",
port->name);
port->name);
+ bitmap_free(trunks);
+ trunks = NULL;
}
}
+ } else if (vlan >= 0 && cfg->n_trunks) {
+ VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+ port->name);
}
if (trunks == NULL
? port->trunks != NULL
}
if (trunks == NULL
? port->trunks != NULL
@@
-3388,8
+3397,6
@@
port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
}
bitmap_free(port->trunks);
port->trunks = trunks;
}
bitmap_free(port->trunks);
port->trunks = trunks;
-
- shash_destroy(&new_ifaces);
}
static void
}
static void
@@
-3414,6
+3421,8
@@
port_destroy(struct port *port)
iface_destroy(port->ifaces[port->n_ifaces - 1]);
}
iface_destroy(port->ifaces[port->n_ifaces - 1]);
}
+ shash_find_and_delete_assert(&br->port_by_name, port->name);
+
del = br->ports[port->port_idx] = br->ports[--br->n_ports];
del->port_idx = port->port_idx;
del = br->ports[port->port_idx] = br->ports[--br->n_ports];
del->port_idx = port->port_idx;
@@
-3435,15
+3444,7
@@
port_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
static struct port *
port_lookup(const struct bridge *br, const char *name)
{
static struct port *
port_lookup(const struct bridge *br, const char *name)
{
- size_t i;
-
- for (i = 0; i < br->n_ports; i++) {
- struct port *port = br->ports[i];
- if (!strcmp(port->name, name)) {
- return port;
- }
- }
- return NULL;
+ return shash_find_data(&br->port_by_name, name);
}
static struct iface *
}
static struct iface *
@@
-3618,6
+3619,8
@@
iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
iface->netdev = NULL;
iface->cfg = if_cfg;
iface->netdev = NULL;
iface->cfg = if_cfg;
+ shash_add_assert(&br->iface_by_name, iface->name, iface);
+
/* Attempt to create the network interface in case it doesn't exist yet. */
if (!iface_is_internal(br, iface->name)) {
error = set_up_iface(if_cfg, iface, true);
/* Attempt to create the network interface in case it doesn't exist yet. */
if (!iface_is_internal(br, iface->name)) {
error = set_up_iface(if_cfg, iface, true);
@@
-3625,14
+3628,13
@@
iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
VLOG_WARN("could not create iface %s: %s", iface->name,
strerror(error));
VLOG_WARN("could not create iface %s: %s", iface->name,
strerror(error));
+ shash_find_and_delete_assert(&br->iface_by_name, iface->name);
free(iface->name);
free(iface);
return NULL;
}
}
free(iface->name);
free(iface);
return NULL;
}
}
- shash_add_assert(&br->iface_by_name, iface->name, iface);
-
if (port->n_ifaces >= port->allocated_ifaces) {
port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
sizeof *port->ifaces);
if (port->n_ifaces >= port->allocated_ifaces) {
port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
sizeof *port->ifaces);