m->wildcards = htonl(wc);
}
+/* Returns a string that describes 'match' in a very literal way, without
+ * interpreting its contents except in a very basic fashion. The returned
+ * string is intended to be fixed-length, so that it is easy to see differences
+ * between two such strings if one is put above another. This is useful for
+ * describing changes made by normalize_match().
+ *
+ * The caller must free the returned string (with free()). */
+char *
+ofp_match_to_literal_string(const struct ofp_match *match)
+{
+ return xasprintf("wildcards=%#10"PRIx32" "
+ " in_port=%5"PRId16" "
+ " dl_src="ETH_ADDR_FMT" "
+ " dl_dst="ETH_ADDR_FMT" "
+ " dl_vlan=%5"PRId16" "
+ " dl_vlan_pcp=%3"PRId8" "
+ " dl_type=%#6"PRIx16" "
+ " nw_tos=%#4"PRIx8" "
+ " nw_proto=%#4"PRIx16" "
+ " nw_src=%#10"PRIx32" "
+ " nw_dst=%#10"PRIx32" "
+ " tp_src=%5"PRId16" "
+ " tp_dst=%5"PRId16,
+ ntohl(match->wildcards),
+ ntohs(match->in_port),
+ ETH_ADDR_ARGS(match->dl_src),
+ ETH_ADDR_ARGS(match->dl_dst),
+ ntohs(match->dl_vlan),
+ match->dl_vlan_pcp,
+ ntohs(match->dl_type),
+ match->nw_tos,
+ match->nw_proto,
+ ntohl(match->nw_src),
+ ntohl(match->nw_dst),
+ ntohs(match->tp_src),
+ ntohs(match->tp_dst));
+}
bool action_outputs_to_port(const union ofp_action *, uint16_t port);
void normalize_match(struct ofp_match *);
+char *ofp_match_to_literal_string(const struct ofp_match *match);
static inline int
ofp_mkerr(uint16_t type, uint16_t code)
handle_flow_mod(struct ofproto *p, struct ofconn *ofconn,
struct ofp_flow_mod *ofm)
{
+ struct ofp_match orig_match;
size_t n_actions;
int error;
return ofp_mkerr(OFPET_FLOW_MOD_FAILED, OFPFMFC_ALL_TABLES_FULL);
}
+ /* Normalize ofp->match. If normalization actually changes anything, then
+ * log the differences. */
+ ofm->match.pad1[0] = ofm->match.pad2[0] = 0;
+ orig_match = ofm->match;
normalize_match(&ofm->match);
+ if (memcmp(&ofm->match, &orig_match, sizeof orig_match)) {
+ static struct vlog_rate_limit normal_rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ if (!VLOG_DROP_INFO(&normal_rl)) {
+ char *old = ofp_match_to_literal_string(&orig_match);
+ char *new = ofp_match_to_literal_string(&ofm->match);
+ VLOG_INFO("%s: normalization changed ofp_match, details:",
+ rconn_get_name(ofconn->rconn));
+ VLOG_INFO(" pre: %s", old);
+ VLOG_INFO("post: %s", new);
+ free(old);
+ free(new);
+ }
+ }
+
if (!ofm->match.wildcards) {
ofm->priority = htons(UINT16_MAX);
}