Previously the out_port of a flow monitor was
checked in ofmonitor_report() using ofoperation_has_out_port().
When ofoperation_has_out_port() was removed so was the call to
it in ofmonitor_report() thus flow monitor updates are longer
filtered on the out_port.
This restores filtering on the out_port by using
ofproto_rule_has_out_port to check the actions of the rule.
If the actions have been changed by a modify actions then
ofpacts_output_to_port() is also used to check the old actions.
This patch also adds a test to exercise out_ports for flow monitors.
This resolves what appears to be a regression introduced by
b20f4073eecd4761 ("ofproto: Do straightforward removal of asynchronous flow
operations.")
Signed-off-by: Simon Horman <horms@verge.net.au>
Signed-off-by: Ben Pfaff <blp@nicira.com>
ofmonitor_report(struct connmgr *mgr, struct rule *rule,
enum nx_flow_update_event event,
enum ofp_flow_removed_reason reason,
- const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid)
+ const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid,
+ const struct rule_actions *old_actions)
OVS_REQUIRES(ofproto_mutex)
{
enum nx_flow_monitor_flags update;
HMAP_FOR_EACH (m, ofconn_node, &ofconn->monitors) {
if (m->flags & update
&& (m->table_id == 0xff || m->table_id == rule->table_id)
+ && (ofproto_rule_has_out_port(rule, m->out_port)
+ || (old_actions
+ && ofpacts_output_to_port(old_actions->ofpacts,
+ old_actions->ofpacts_len,
+ m->out_port)))
&& cls_rule_is_loose_match(&rule->cr, &m->match)) {
flags |= m->flags;
}
#include "ofp-errors.h"
#include "ofp-util.h"
#include "ofproto.h"
+#include "ofproto-provider.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
void ofmonitor_report(struct connmgr *, struct rule *,
enum nx_flow_update_event, enum ofp_flow_removed_reason,
- const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid)
+ const struct ofconn *abbrev_ofconn, ovs_be32 abbrev_xid,
+ const struct rule_actions *old_actions)
OVS_REQUIRES(ofproto_mutex);
void ofmonitor_flush(struct connmgr *) OVS_REQUIRES(ofproto_mutex);
const struct rule_actions *rule_actions_create(const struct ofpact *, size_t);
void rule_actions_destroy(const struct rule_actions *);
+bool ofproto_rule_has_out_port(const struct rule *, ofp_port_t port)
+ OVS_REQUIRES(ofproto_mutex);
/* A set of rules to which an OpenFlow operation applies. */
struct rule_collection {
/* Returns true if 'rule' has an OpenFlow OFPAT_OUTPUT or OFPAT_ENQUEUE action
* that outputs to 'port' (output to OFPP_FLOOD and OFPP_ALL doesn't count). */
-static bool
+bool
ofproto_rule_has_out_port(const struct rule *rule, ofp_port_t port)
OVS_REQUIRES(ofproto_mutex)
{
}
ofmonitor_report(ofproto->connmgr, rule, NXFME_ADDED, 0,
- req ? req->ofconn : NULL, req ? req->xid : 0);
+ req ? req->ofconn : NULL, req ? req->xid : 0, NULL);
return req ? send_buffered_packet(req->ofconn, fm->buffer_id, rule) : 0;
}
if (change_actions) {
ovsrcu_set(&rule->actions, rule_actions_create(fm->ofpacts,
fm->ofpacts_len));
- rule_actions_destroy(actions);
}
if (change_actions || reset_counters) {
if (event != NXFME_MODIFIED || change_actions || change_cookie) {
ofmonitor_report(ofproto->connmgr, rule, event, 0,
- req ? req->ofconn : NULL, req ? req->xid : 0);
+ req ? req->ofconn : NULL, req ? req->xid : 0,
+ change_actions ? actions : NULL);
}
if (change_actions) {
learned_cookies_inc(ofproto, rule_get_actions(rule));
learned_cookies_dec(ofproto, actions, &dead_cookies);
+ rule_actions_destroy(actions);
}
}
learned_cookies_flush(ofproto, &dead_cookies);
ofproto_rule_send_removed(rule, reason);
ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
- req ? req->ofconn : NULL, req ? req->xid : 0);
+ req ? req->ofconn : NULL, req ? req->xid : 0,
+ NULL);
oftable_remove_rule(rule);
ofproto->ofproto_class->rule_delete(rule);
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - flow monitoring with out_port])
+AT_KEYWORDS([monitor])
+OVS_VSWITCHD_START
+
+ovs-ofctl add-flow br0 in_port=0,dl_vlan=121,actions=output:1
+ovs-ofctl add-flow br0 in_port=0,dl_vlan=122,actions=output:1
+ovs-ofctl add-flow br0 in_port=0,dl_vlan=123,actions=output:2
+
+# Start a monitor watching the flow table and check the initial reply.
+ovs-ofctl monitor br0 watch:out_port=2 --detach --no-chdir --pidfile >monitor.log 2>&1
+AT_CAPTURE_FILE([monitor.log])
+ovs-appctl -t ovs-ofctl ofctl/barrier
+AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
+ [NXST_FLOW_MONITOR reply:
+ event=ADDED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
+OFPT_BARRIER_REPLY:
+])
+
+ovs-appctl -t ovs-ofctl ofctl/set-output-file monitor.log
+
+# Add, modify flows and check the updates.
+ovs-ofctl mod-flows br0 dl_vlan=121,actions=drop
+ovs-ofctl mod-flows br0 dl_vlan=122,actions=output:1,output:2
+ovs-appctl -t ovs-ofctl ofctl/barrier
+
+ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:1,output:2
+ovs-appctl -t ovs-ofctl ofctl/barrier
+
+ovs-ofctl mod-flows br0 dl_vlan=122,actions=output:1
+ovs-appctl -t ovs-ofctl ofctl/barrier
+ovs-ofctl mod-flows br0 dl_vlan=123,actions=output:2
+ovs-appctl -t ovs-ofctl ofctl/barrier
+
+AT_CHECK([sed 's/ (xid=0x[[1-9a-fA-F]][[0-9a-fA-F]]*)//' monitor.log], [0],
+[NXST_FLOW_MONITOR reply (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1,output:2
+OFPT_BARRIER_REPLY:
+NXST_FLOW_MONITOR reply (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:1,output:2
+OFPT_BARRIER_REPLY:
+NXST_FLOW_MONITOR reply (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=122 actions=output:1
+OFPT_BARRIER_REPLY:
+NXST_FLOW_MONITOR reply (xid=0x0):
+ event=MODIFIED table=0 cookie=0 in_port=0,dl_vlan=123 actions=output:2
+OFPT_BARRIER_REPLY:
+])
+
+ovs-appctl -t ovs-ofctl exit
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto - flow monitoring pause and resume])
AT_KEYWORDS([monitor])