ovsdb-data: Short-circuit ovsdb_datum_includes_all() in trivial case.
[openvswitch] / lib / ofp-print.c
index 3b9c582639ca1baa1f5ed37f9d31642ef19dc950..67edc543f690cad3c0a5b8e084afae1846a08ad9 100644 (file)
@@ -31,6 +31,7 @@
 #include "compiler.h"
 #include "dynamic-string.h"
 #include "flow.h"
+#include "learn.h"
 #include "multipath.h"
 #include "nx-match.h"
 #include "ofp-util.h"
@@ -48,104 +49,98 @@ static void ofp_print_error(struct ds *, int error);
 
 
 /* Returns a string that represents the contents of the Ethernet frame in the
- * 'len' bytes starting at 'data' to 'stream' as output by tcpdump.
- * 'total_len' specifies the full length of the Ethernet frame (of which 'len'
- * bytes were captured).
- *
- * The caller must free the returned string.
- *
- * This starts and kills a tcpdump subprocess so it's quite expensive. */
+ * 'len' bytes starting at 'data'.  The caller must free the returned string.*/
 char *
-ofp_packet_to_string(const void *data, size_t len, size_t total_len OVS_UNUSED)
+ofp_packet_to_string(const void *data, size_t len)
 {
     struct ds ds = DS_EMPTY_INITIALIZER;
     struct ofpbuf buf;
-
-    char command[128];
-    FILE *pcap;
-    FILE *tcpdump;
-    int status;
-    int c;
+    struct flow flow;
 
     ofpbuf_use_const(&buf, data, len);
-
-    pcap = tmpfile();
-    if (!pcap) {
-        ovs_error(errno, "tmpfile");
-        return xstrdup("<error>");
-    }
-    pcap_write_header(pcap);
-    pcap_write(pcap, &buf);
-    fflush(pcap);
-    if (ferror(pcap)) {
-        ovs_error(errno, "error writing temporary file");
-    }
-    rewind(pcap);
-
-    snprintf(command, sizeof command, "/usr/sbin/tcpdump -t -e -n -r /dev/fd/%d 2>/dev/null",
-             fileno(pcap));
-    tcpdump = popen(command, "r");
-    fclose(pcap);
-    if (!tcpdump) {
-        ovs_error(errno, "exec(\"%s\")", command);
-        return xstrdup("<error>");
+    flow_extract(&buf, 0, 0, 0, &flow);
+    flow_format(&ds, &flow);
+
+    if (buf.l7) {
+        if (flow.nw_proto == IPPROTO_TCP) {
+            struct tcp_header *th = buf.l4;
+            ds_put_format(&ds, " tcp_csum:%"PRIx16,
+                          ntohs(th->tcp_csum));
+        } else if (flow.nw_proto == IPPROTO_UDP) {
+            struct udp_header *uh = buf.l4;
+            ds_put_format(&ds, " udp_csum:%"PRIx16,
+                          ntohs(uh->udp_csum));
+        }
     }
 
-    while ((c = getc(tcpdump)) != EOF) {
-        ds_put_char(&ds, c);
-    }
+    ds_put_char(&ds, '\n');
 
-    status = pclose(tcpdump);
-    if (WIFEXITED(status)) {
-        if (WEXITSTATUS(status))
-            ovs_error(0, "tcpdump exited with status %d", WEXITSTATUS(status));
-    } else if (WIFSIGNALED(status)) {
-        ovs_error(0, "tcpdump exited with signal %d", WTERMSIG(status));
-    }
     return ds_cstr(&ds);
 }
 
 static void
-ofp_print_packet_in(struct ds *string, const struct ofp_packet_in *op,
+ofp_print_packet_in(struct ds *string, const struct ofp_header *oh,
                     int verbosity)
 {
-    size_t len = ntohs(op->header.length);
-    size_t data_len;
+    struct ofputil_packet_in pin;
+    int error;
+    int i;
 
-    ds_put_format(string, " total_len=%"PRIu16" in_port=",
-                  ntohs(op->total_len));
-    ofputil_format_port(ntohs(op->in_port), string);
+    error = ofputil_decode_packet_in(&pin, oh);
+    if (error) {
+        ofp_print_error(string, error);
+        return;
+    }
 
-    if (op->reason == OFPR_ACTION)
+    if (pin.table_id) {
+        ds_put_format(string, " table_id=%"PRIu8, pin.table_id);
+    }
+
+    if (pin.cookie) {
+        ds_put_format(string, " cookie=0x%"PRIx64, ntohll(pin.cookie));
+    }
+
+    ds_put_format(string, " total_len=%"PRIu16" in_port=", pin.total_len);
+    ofputil_format_port(pin.fmd.in_port, string);
+
+    if (pin.fmd.tun_id_mask) {
+        ds_put_format(string, " tun_id=0x%"PRIx64, ntohll(pin.fmd.tun_id));
+        if (pin.fmd.tun_id_mask != htonll(UINT64_MAX)) {
+            ds_put_format(string, "/0x%"PRIx64, ntohll(pin.fmd.tun_id_mask));
+        }
+    }
+
+    for (i = 0; i < FLOW_N_REGS; i++) {
+        if (pin.fmd.reg_masks[i]) {
+            ds_put_format(string, " reg%d=0x%"PRIx32, i, pin.fmd.regs[i]);
+            if (pin.fmd.reg_masks[i] != UINT32_MAX) {
+                ds_put_format(string, "/0x%"PRIx32, pin.fmd.reg_masks[i]);
+            }
+        }
+    }
+
+    if (pin.reason == OFPR_ACTION) {
         ds_put_cstr(string, " (via action)");
-    else if (op->reason != OFPR_NO_MATCH)
-        ds_put_format(string, " (***reason %"PRIu8"***)", op->reason);
+    } else if (pin.reason != OFPR_NO_MATCH) {
+        ds_put_format(string, " (***reason %"PRIu8"***)", pin.reason);
+    }
 
-    data_len = len - offsetof(struct ofp_packet_in, data);
-    ds_put_format(string, " data_len=%zu", data_len);
-    if (op->buffer_id == htonl(UINT32_MAX)) {
+    ds_put_format(string, " data_len=%zu", pin.packet_len);
+    if (pin.buffer_id == UINT32_MAX) {
         ds_put_format(string, " (unbuffered)");
-        if (ntohs(op->total_len) != data_len)
+        if (pin.total_len != pin.packet_len) {
             ds_put_format(string, " (***total_len != data_len***)");
+        }
     } else {
-        ds_put_format(string, " buffer=0x%08"PRIx32, ntohl(op->buffer_id));
-        if (ntohs(op->total_len) < data_len)
+        ds_put_format(string, " buffer=0x%08"PRIx32, pin.buffer_id);
+        if (pin.total_len < pin.packet_len) {
             ds_put_format(string, " (***total_len < data_len***)");
+        }
     }
     ds_put_char(string, '\n');
 
     if (verbosity > 0) {
-        struct flow flow;
-        struct ofpbuf packet;
-
-        ofpbuf_use_const(&packet, op->data, data_len);
-        flow_extract(&packet, 0, ntohs(op->in_port), &flow);
-        flow_format(string, &flow);
-        ds_put_char(string, '\n');
-    }
-    if (verbosity > 1) {
-        char *packet = ofp_packet_to_string(op->data, data_len,
-                                            ntohs(op->total_len));
+        char *packet = ofp_packet_to_string(pin.packet, pin.packet_len);
         ds_put_cstr(string, packet);
         free(packet);
     }
@@ -333,6 +328,14 @@ ofp_print_action(struct ds *s, const union ofp_action *a,
                               nxm_decode_n_bits(naor->ofs_nbits));
         break;
 
+    case OFPUTIL_NXAST_LEARN:
+        learn_format((const struct nx_action_learn *) a, s);
+        break;
+
+    case OFPUTIL_NXAST_EXIT:
+        ds_put_cstr(s, "exit");
+        break;
+
     default:
         break;
     }
@@ -394,7 +397,7 @@ ofp_print_packet_out(struct ds *string, const struct ofp_packet_out *opo,
         ds_put_format(string, " data_len=%d", data_len);
         if (verbosity > 0 && len > sizeof *opo) {
             char *packet = ofp_packet_to_string(
-                    (uint8_t *)opo->actions + actions_len, data_len, data_len);
+                    (uint8_t *) opo->actions + actions_len, data_len);
             ds_put_char(string, '\n');
             ds_put_cstr(string, packet);
             free(packet);
@@ -599,21 +602,9 @@ ofp_print_switch_config(struct ds *string, const struct ofp_switch_config *osc)
 
     flags = ntohs(osc->flags);
 
-    ds_put_cstr(string, " frags=");
-    switch (flags & OFPC_FRAG_MASK) {
-    case OFPC_FRAG_NORMAL:
-        ds_put_cstr(string, "normal");
-        flags &= ~OFPC_FRAG_MASK;
-        break;
-    case OFPC_FRAG_DROP:
-        ds_put_cstr(string, "drop");
-        flags &= ~OFPC_FRAG_MASK;
-        break;
-    case OFPC_FRAG_REASM:
-        ds_put_cstr(string, "reassemble");
-        flags &= ~OFPC_FRAG_MASK;
-        break;
-    }
+    ds_put_format(string, " frags=%s", ofputil_frag_handling_to_string(flags));
+    flags &= ~OFPC_FRAG_MASK;
+
     if (flags) {
         ds_put_format(string, " ***unknown flags 0x%04"PRIx16"***", flags);
     }
@@ -734,9 +725,9 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity)
                "%u", om->nw_tos);
     if (om->nw_proto == IPPROTO_ICMP) {
         print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity,
-                   "%d", ntohs(om->icmp_type));
+                   "%d", ntohs(om->tp_src));
         print_wild(&f, "icmp_code=", w & OFPFW_ICMP_CODE, verbosity,
-                   "%d", ntohs(om->icmp_code));
+                   "%d", ntohs(om->tp_dst));
     } else {
         print_wild(&f, "tp_src=", w & OFPFW_TP_SRC, verbosity,
                    "%d", ntohs(om->tp_src));
@@ -942,15 +933,11 @@ ofp_print_error_msg(struct ds *string, const struct ofp_error_msg *oem)
         ds_put_printable(string, payload, payload_len);
         break;
 
-    case OFPET_BAD_REQUEST:
+    default:
         s = ofp_to_string(payload, payload_len, 1);
         ds_put_cstr(string, s);
         free(s);
         break;
-
-    default:
-        ds_put_hex_dump(string, payload, payload_len, 0, true);
-        break;
     }
 }
 
@@ -1048,7 +1035,9 @@ ofp_print_flow_stats_reply(struct ds *string, const struct ofp_header *oh)
         }
 
         cls_rule_format(&fs.rule, string);
-        ds_put_char(string, ' ');
+        if (string->string[string->length - 1] != ' ') {
+            ds_put_char(string, ' ');
+        }
         ofp_print_actions(string, fs.actions, fs.n_actions);
      }
 }
@@ -1283,6 +1272,20 @@ ofp_print_nxt_set_flow_format(struct ds *string,
     }
 }
 
+static void
+ofp_print_nxt_set_packet_in_format(struct ds *string,
+                                   const struct nxt_set_packet_in_format *nspf)
+{
+    uint32_t format = ntohl(nspf->format);
+
+    ds_put_cstr(string, " format=");
+    if (ofputil_packet_in_format_is_valid(format)) {
+        ds_put_cstr(string, ofputil_packet_in_format_to_string(format));
+    } else {
+        ds_put_format(string, "%"PRIu32, format);
+    }
+}
+
 static void
 ofp_to_string__(const struct ofp_header *oh,
                 const struct ofputil_msg_type *type, struct ds *string,
@@ -1330,6 +1333,7 @@ ofp_to_string__(const struct ofp_header *oh,
         break;
 
     case OFPUTIL_OFPT_PACKET_IN:
+    case OFPUTIL_NXT_PACKET_IN:
         ofp_print_packet_in(string, msg, verbosity);
         break;
 
@@ -1433,6 +1437,10 @@ ofp_to_string__(const struct ofp_header *oh,
         ofp_print_nxt_set_flow_format(string, msg);
         break;
 
+    case OFPUTIL_NXT_SET_PACKET_IN_FORMAT:
+        ofp_print_nxt_set_packet_in_format(string, msg);
+        break;
+
     case OFPUTIL_NXT_FLOW_MOD:
         ofp_print_flow_mod(string, msg, code, verbosity);
         break;
@@ -1597,12 +1605,9 @@ ofp_print(FILE *stream, const void *oh, size_t len, int verbosity)
 }
 
 /* Dumps the contents of the Ethernet frame in the 'len' bytes starting at
- * 'data' to 'stream' using tcpdump.  'total_len' specifies the full length of
- * the Ethernet frame (of which 'len' bytes were captured).
- *
- * This starts and kills a tcpdump subprocess so it's quite expensive. */
+ * 'data' to 'stream'. */
 void
-ofp_print_packet(FILE *stream, const void *data, size_t len, size_t total_len)
+ofp_print_packet(FILE *stream, const void *data, size_t len)
 {
-    print_and_free(stream, ofp_packet_to_string(data, len, total_len));
+    print_and_free(stream, ofp_packet_to_string(data, len));
 }