netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / utilities / ovs-ofctl.c
index 0d990aa..7bcfc66 100644 (file)
 
 VLOG_DEFINE_THIS_MODULE(ofctl);
 
-/* --bundle: Use OpenFlow 1.4 bundle for making the flow table change atomic.
- * NOTE: Also the flow mod will use OpenFlow 1.4, so the semantics may be
- * different (see the comment in parse_options() for details).
+/* --bundle: Use OpenFlow 1.3+ bundle for making the flow table change atomic.
+ * NOTE: If OpenFlow 1.3 or higher is not selected with the '-O' option,
+ * OpenFlow 1.4 will be implicitly selected.  Also the flow mod will use
+ * OpenFlow 1.4, so the semantics may be different (see the comment in
+ * parse_options() for details).
  */
 static bool bundle = false;
 
@@ -308,13 +310,14 @@ parse_options(int argc, char *argv[])
     free(short_options);
 
     /* Implicit OpenFlow 1.4 with the '--bundle' option. */
-    if (bundle) {
+    if (bundle && !(get_allowed_ofp_versions() &
+                    ofputil_protocols_to_version_bitmap(OFPUTIL_P_OF13_UP))) {
         /* Add implicit allowance for OpenFlow 1.4. */
         add_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
                                      OFPUTIL_P_OF14_OXM));
-        /* Remove all prior versions. */
+        /* Remove all versions that do not support bundles. */
         mask_allowed_ofp_versions(ofputil_protocols_to_version_bitmap(
-                                     OFPUTIL_P_OF14_UP));
+                                     OFPUTIL_P_OF13_UP));
     }
     versions = get_allowed_ofp_versions();
     version_protocols = ofputil_protocols_from_version_bitmap(versions);
@@ -1317,8 +1320,8 @@ bundle_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
 
     list_init(&requests);
 
-    /* Bundles need OpenFlow 1.4+. */
-    usable_protocols &= OFPUTIL_P_OF14_UP;
+    /* Bundles need OpenFlow 1.3+. */
+    usable_protocols &= OFPUTIL_P_OF13_UP;
     protocol = open_vconn_for_flow_mod(remote, &vconn, usable_protocols);
 
     for (i = 0; i < n_fms; i++) {
@@ -1633,9 +1636,13 @@ ofctl_unblock(struct unixctl_conn *conn, int argc OVS_UNUSED,
 /* Prints to stdout all of the messages received on 'vconn'.
  *
  * Iff 'reply_to_echo_requests' is true, sends a reply to any echo request
- * received on 'vconn'. */
+ * received on 'vconn'.
+ *
+ * If 'resume_continuations' is true, sends an NXT_RESUME in reply to any
+ * NXT_PACKET_IN2 that includes a continuation. */
 static void
-monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
+monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests,
+              bool resume_continuations)
 {
     struct barrier_aux barrier_aux = { vconn, NULL };
     struct unixctl_server *server;
@@ -1663,6 +1670,10 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
 
     daemonize_complete();
 
+    enum ofp_version version = vconn_get_version(vconn);
+    enum ofputil_protocol protocol
+        = ofputil_protocol_from_ofp_version(version);
+
     for (;;) {
         struct ofpbuf *b;
         int retval;
@@ -1708,6 +1719,36 @@ monitor_vconn(struct vconn *vconn, bool reply_to_echo_requests)
                     }
                 }
                 break;
+
+            case OFPTYPE_PACKET_IN:
+                if (resume_continuations) {
+                    struct ofputil_packet_in pin;
+                    struct ofpbuf continuation;
+
+                    error = ofputil_decode_packet_in(b->data, true, &pin,
+                                                     NULL, NULL,
+                                                     &continuation);
+                    if (error) {
+                        fprintf(stderr, "decoding packet-in failed: %s",
+                                ofperr_to_string(error));
+                    } else if (continuation.size) {
+                        struct ofpbuf *reply;
+
+                        reply = ofputil_encode_resume(&pin, &continuation,
+                                                      protocol);
+
+                        fprintf(stderr, "send: ");
+                        ofp_print(stderr, reply->data, reply->size,
+                                  verbosity + 2);
+                        fflush(stderr);
+
+                        retval = vconn_send_block(vconn, reply);
+                        if (retval) {
+                            ovs_fatal(retval, "failed to send NXT_RESUME");
+                        }
+                    }
+                }
+                break;
             }
             ofpbuf_delete(b);
         }
@@ -1758,6 +1799,7 @@ ofctl_monitor(struct ovs_cmdl_context *ctx)
     }
 
     open_vconn(ctx->argv[1], &vconn);
+    bool resume_continuations = false;
     for (i = 2; i < ctx->argc; i++) {
         const char *arg = ctx->argv[i];
 
@@ -1784,6 +1826,16 @@ ofctl_monitor(struct ovs_cmdl_context *ctx)
             ofputil_append_flow_monitor_request(&fmr, msg);
             dump_transaction(vconn, msg);
             fflush(stdout);
+        } else if (!strcmp(arg, "resume")) {
+            /* This option is intentionally undocumented because it is meant
+             * only for testing. */
+            resume_continuations = true;
+
+            /* Set miss_send_len to ensure that we get packet-ins. */
+            struct ofputil_switch_config config;
+            fetch_switch_config(vconn, &config);
+            config.miss_send_len = UINT16_MAX;
+            set_switch_config(vconn, &config);
         } else {
             ovs_fatal(0, "%s: unsupported \"monitor\" argument", arg);
         }
@@ -1805,7 +1857,7 @@ ofctl_monitor(struct ovs_cmdl_context *ctx)
         }
     }
 
-    monitor_vconn(vconn, true);
+    monitor_vconn(vconn, true, resume_continuations);
 }
 
 static void
@@ -1814,7 +1866,7 @@ ofctl_snoop(struct ovs_cmdl_context *ctx)
     struct vconn *vconn;
 
     open_vconn__(ctx->argv[1], SNOOP, &vconn);
-    monitor_vconn(vconn, false);
+    monitor_vconn(vconn, false, false);
 }
 
 static void
@@ -3610,35 +3662,43 @@ ofctl_parse_ofp11_match(struct ovs_cmdl_context *ctx OVS_UNUSED)
     ds_destroy(&in);
 }
 
-/* "parse-pcap PCAP": read packets from PCAP and print their flows. */
+/* "parse-pcap PCAP...": read packets from each PCAP file and print their
+ * flows. */
 static void
 ofctl_parse_pcap(struct ovs_cmdl_context *ctx)
 {
-    FILE *pcap;
+    int error = 0;
+    for (int i = 1; i < ctx->argc; i++) {
+        const char *filename = ctx->argv[i];
+        FILE *pcap = ovs_pcap_open(filename, "rb");
+        if (!pcap) {
+            error = errno;
+            ovs_error(error, "%s: open failed", filename);
+            continue;
+        }
 
-    pcap = ovs_pcap_open(ctx->argv[1], "rb");
-    if (!pcap) {
-        ovs_fatal(errno, "%s: open failed", ctx->argv[1]);
-    }
+        for (;;) {
+            struct dp_packet *packet;
+            struct flow flow;
+            int retval;
 
-    for (;;) {
-        struct dp_packet *packet;
-        struct flow flow;
-        int error;
+            retval = ovs_pcap_read(pcap, &packet, NULL);
+            if (retval == EOF) {
+                break;
+            } else if (retval) {
+                error = retval;
+                ovs_error(error, "%s: read failed", filename);
+            }
 
-        error = ovs_pcap_read(pcap, &packet, NULL);
-        if (error == EOF) {
-            break;
-        } else if (error) {
-            ovs_fatal(error, "%s: read failed", ctx->argv[1]);
+            pkt_metadata_init(&packet->md, ODPP_NONE);
+            flow_extract(packet, &flow);
+            flow_print(stdout, &flow);
+            putchar('\n');
+            dp_packet_delete(packet);
         }
-
-        pkt_metadata_init(&packet->md, ODPP_NONE);
-        flow_extract(packet, &flow);
-        flow_print(stdout, &flow);
-        putchar('\n');
-        dp_packet_delete(packet);
+        fclose(pcap);
     }
+    exit(error);
 }
 
 /* "check-vlan VLAN_TCI VLAN_TCI_MASK": converts the specified vlan_tci and
@@ -3976,7 +4036,7 @@ static const struct ovs_cmdl_command all_commands[] = {
     { "parse-instructions", NULL, 1, 1, ofctl_parse_instructions },
     { "parse-ofp10-match", NULL, 0, 0, ofctl_parse_ofp10_match },
     { "parse-ofp11-match", NULL, 0, 0, ofctl_parse_ofp11_match },
-    { "parse-pcap", NULL, 1, 1, ofctl_parse_pcap },
+    { "parse-pcap", NULL, 1, INT_MAX, ofctl_parse_pcap },
     { "check-vlan", NULL, 2, 2, ofctl_check_vlan },
     { "print-error", NULL, 1, 1, ofctl_print_error },
     { "encode-error-reply", NULL, 2, 2, ofctl_encode_error_reply },