#include "lacp.h"
#include "learn.h"
#include "mac-learning.h"
+#include "mcast-snooping.h"
#include "meta-flow.h"
#include "multipath.h"
#include "netdev-vport.h"
COVERAGE_DEFINE(ofproto_dpif_expired);
COVERAGE_DEFINE(packet_in_overflow);
-/* No bfd/cfm status change. */
-#define NO_STATUS_CHANGE -1
-
struct flow_miss;
struct rule_dpif {
* recently been processed by a revalidator. */
struct ovs_mutex stats_mutex;
struct dpif_flow_stats stats OVS_GUARDED;
+
+ /* If non-zero then the recirculation id that has
+ * been allocated for use with this rule.
+ * The recirculation id and associated internal flow should
+ * be freed when the rule is freed */
+ uint32_t recirc_id;
};
/* RULE_CAST() depends on this. */
REV_PORT_TOGGLED, /* Port enabled or disabled by CFM, LACP, ...*/
REV_FLOW_TABLE, /* Flow table changed. */
REV_MAC_LEARNING, /* Mac learning changed. */
+ REV_MCAST_SNOOPING, /* Multicast snooping changed. */
};
COVERAGE_DEFINE(rev_reconfigure);
COVERAGE_DEFINE(rev_stp);
COVERAGE_DEFINE(rev_port_toggled);
COVERAGE_DEFINE(rev_flow_table);
COVERAGE_DEFINE(rev_mac_learning);
+COVERAGE_DEFINE(rev_mcast_snooping);
/* All datapaths of a given type share a single dpif backer instance. */
struct dpif_backer {
struct dpif_ipfix *ipfix;
struct hmap bundles; /* Contains "struct ofbundle"s. */
struct mac_learning *ml;
+ struct mcast_snooping *ms;
bool has_bonded_bundles;
bool lacp_enabled;
struct mbridge *mbridge;
case REV_PORT_TOGGLED: COVERAGE_INC(rev_port_toggled); break;
case REV_FLOW_TABLE: COVERAGE_INC(rev_flow_table); break;
case REV_MAC_LEARNING: COVERAGE_INC(rev_mac_learning); break;
+ case REV_MCAST_SNOOPING: COVERAGE_INC(rev_mcast_snooping); break;
}
backer->need_revalidate = 0;
xlate_ofproto_set(ofproto, ofproto->up.name,
ofproto->backer->dpif, ofproto->miss_rule,
ofproto->no_packet_in_rule, ofproto->ml,
- ofproto->stp, ofproto->mbridge,
+ ofproto->stp, ofproto->ms, ofproto->mbridge,
ofproto->sflow, ofproto->ipfix,
ofproto->netflow, ofproto->up.frag_handling,
ofproto->up.forward_bpdu,
ofproto->dump_seq = 0;
hmap_init(&ofproto->bundles);
ofproto->ml = mac_learning_create(MAC_ENTRY_DEFAULT_IDLE_TIME);
+ ofproto->ms = NULL;
ofproto->mbridge = mbridge_create();
ofproto->has_bonded_bundles = false;
ofproto->lacp_enabled = false;
match_init_catchall(&match);
match_set_reg(&match, 0, id);
- error = ofproto_dpif_add_internal_flow(ofproto, &match, 0, ofpacts, &rule);
+ error = ofproto_dpif_add_internal_flow(ofproto, &match, 0, 0, ofpacts,
+ &rule);
*rulep = error ? NULL : rule_dpif_cast(rule);
return error;
match_init_catchall(&match);
match_set_recirc_id(&match, 0);
- error = ofproto_dpif_add_internal_flow(ofproto, &match, 2, &ofpacts,
+ error = ofproto_dpif_add_internal_flow(ofproto, &match, 2, 0, &ofpacts,
&unused_rulep);
if (error) {
return error;
*/
ofpbuf_clear(&ofpacts);
match_init_catchall(&match);
- error = ofproto_dpif_add_internal_flow(ofproto, &match, 1, &ofpacts,
+ error = ofproto_dpif_add_internal_flow(ofproto, &match, 1, 0, &ofpacts,
&unused_rulep);
return error;
dpif_sflow_unref(ofproto->sflow);
hmap_destroy(&ofproto->bundles);
mac_learning_unref(ofproto->ml);
+ mcast_snooping_unref(ofproto->ms);
hmap_destroy(&ofproto->vlandev_map);
hmap_destroy(&ofproto->realdev_vid_map);
ovs_rwlock_wrlock(&ofproto->ml->rwlock);
mac_learning_flush(ofproto->ml);
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ mcast_snooping_mdb_flush(ofproto->ms);
}
/* Always updates the ofproto->pins_seqno to avoid frequent wakeup during
}
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ if (mcast_snooping_run(ofproto->ms)) {
+ ofproto->backer->need_revalidate = REV_MCAST_SNOOPING;
+ }
+
new_dump_seq = seq_read(udpif_dump_seq(ofproto->backer->udpif));
if (ofproto->dump_seq != new_dump_seq) {
struct rule *rule, *next_rule;
ovs_rwlock_rdlock(&ofproto->ml->rwlock);
mac_learning_wait(ofproto->ml);
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ mcast_snooping_wait(ofproto->ms);
stp_wait(ofproto);
if (ofproto->backer->need_revalidate) {
/* Shouldn't happen, but if it does just go around again. */
return error;
}
+static bool
+cfm_status_changed(struct ofport *ofport_)
+{
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+
+ return ofport->cfm ? cfm_check_status_change(ofport->cfm) : true;
+}
+
static int
get_cfm_status(const struct ofport *ofport_,
- struct ofproto_cfm_status *status)
+ struct cfm_status *status)
{
struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
int ret = 0;
if (ofport->cfm) {
- if (cfm_check_status_change(ofport->cfm)) {
- status->faults = cfm_get_fault(ofport->cfm);
- status->flap_count = cfm_get_flap_count(ofport->cfm);
- status->remote_opstate = cfm_get_opup(ofport->cfm);
- status->health = cfm_get_health(ofport->cfm);
- cfm_get_remote_mpids(ofport->cfm, &status->rmps, &status->n_rmps);
- } else {
- ret = NO_STATUS_CHANGE;
- }
+ cfm_get_status(ofport->cfm, status);
} else {
ret = ENOENT;
}
return 0;
}
+static bool
+bfd_status_changed(struct ofport *ofport_)
+{
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+
+ return ofport->bfd ? bfd_check_status_change(ofport->bfd) : true;
+}
+
static int
get_bfd_status(struct ofport *ofport_, struct smap *smap)
{
int ret = 0;
if (ofport->bfd) {
- if (bfd_check_status_change(ofport->bfd)) {
- bfd_get_status(ofport->bfd, smap);
- } else {
- ret = NO_STATUS_CHANGE;
- }
+ bfd_get_status(ofport->bfd, smap);
} else {
ret = ENOENT;
}
ovs_rwlock_wrlock(&ofproto->ml->rwlock);
mac_learning_flush(ofproto->ml);
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ mcast_snooping_mdb_flush(ofproto->ms);
}
fwd_change = stp_forward_in_state(ofport->stp_state)
!= stp_forward_in_state(state);
ovs_rwlock_wrlock(&ofproto->ml->rwlock);
mac_learning_flush(ofproto->ml);
ovs_rwlock_unlock(&ofproto->ml->rwlock);
+ mcast_snooping_mdb_flush(ofproto->ms);
}
}
}
long long int now = time_msec();
int reason = -1;
- ovs_assert(!rule->up.pending);
-
hard_timeout = rule->up.hard_timeout;
idle_timeout = rule->up.idle_timeout;
return rule_get_actions(&rule->up);
}
+/* Sets 'rule''s recirculation id. */
+static void
+rule_dpif_set_recirc_id(struct rule_dpif *rule, uint32_t id)
+ OVS_REQUIRES(rule->up.mutex)
+{
+ ovs_assert(!rule->recirc_id);
+ rule->recirc_id = id;
+}
+
+/* Returns 'rule''s recirculation id. */
+uint32_t
+rule_dpif_get_recirc_id(struct rule_dpif *rule)
+ OVS_REQUIRES(rule->up.mutex)
+{
+ if (!rule->recirc_id) {
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+
+ rule_dpif_set_recirc_id(rule, ofproto_dpif_alloc_recirc_id(ofproto));
+ }
+ return rule->recirc_id;
+}
+
+/* Sets 'rule''s recirculation id. */
+void
+rule_set_recirc_id(struct rule *rule_, uint32_t id)
+{
+ struct rule_dpif *rule = rule_dpif_cast(rule_);
+
+ ovs_mutex_lock(&rule->up.mutex);
+ rule_dpif_set_recirc_id(rule, id);
+ ovs_mutex_unlock(&rule->up.mutex);
+}
+
/* Lookup 'flow' in table 0 of 'ofproto''s classifier.
* If 'wc' is non-null, sets the fields that were relevant as part of
* the lookup. Returns the table_id where a match or miss occurred.
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
ofproto->backer->need_revalidate = REV_FLOW_TABLE;
- ofoperation_complete(rule->up.pending, 0);
}
static struct rule_dpif *rule_dpif_cast(const struct rule *rule)
rule->stats.n_packets = 0;
rule->stats.n_bytes = 0;
rule->stats.used = rule->up.modified;
+ rule->recirc_id = 0;
+
return 0;
}
-static void
+static enum ofperr
rule_insert(struct rule *rule_)
OVS_REQUIRES(ofproto_mutex)
{
struct rule_dpif *rule = rule_dpif_cast(rule_);
complete_operation(rule);
+ return 0;
}
static void
rule_destruct(struct rule *rule_)
{
struct rule_dpif *rule = rule_dpif_cast(rule_);
+
ovs_mutex_destroy(&rule->stats_mutex);
+ if (rule->recirc_id) {
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+
+ ofproto_dpif_free_recirc_id(ofproto, rule->recirc_id);
+ }
}
static void
int
ofproto_dpif_add_internal_flow(struct ofproto_dpif *ofproto,
const struct match *match, int priority,
+ uint16_t idle_timeout,
const struct ofpbuf *ofpacts,
struct rule **rulep)
{
fm.modify_cookie = false;
fm.table_id = TBL_INTERNAL;
fm.command = OFPFC_ADD;
- fm.idle_timeout = 0;
+ fm.idle_timeout = idle_timeout;
fm.hard_timeout = 0;
fm.buffer_id = 0;
fm.out_port = 0;
rule_dealloc,
rule_get_stats,
rule_execute,
+ NULL, /* rule_premodify_actions */
rule_modify_actions,
set_frag_handling,
packet_out,
set_sflow,
set_ipfix,
set_cfm,
+ cfm_status_changed,
get_cfm_status,
set_bfd,
+ bfd_status_changed,
get_bfd_status,
set_stp,
get_stp_status,