[ovs-dev] [learning v2 11/19] ofproto-dpif: Add -packet option to ofproto/trace command.

Ben Pfaff blp at nicira.com
Fri Aug 19 22:28:26 UTC 2011


---
 lib/flow.c                  |   71 +++++++++++++++++++++++++++++++++++++++++++
 lib/flow.h                  |    2 +
 ofproto/ofproto-dpif.c      |   10 +++++-
 ofproto/ofproto-unixctl.man |   24 ++++++++++----
 4 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/lib/flow.c b/lib/flow.c
index 460771c..2599de6 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -888,3 +888,74 @@ flow_hash_fields_valid(enum nx_hash_fields fields)
     return fields == NX_HASH_FIELDS_ETH_SRC
         || fields == NX_HASH_FIELDS_SYMMETRIC_L4;
 }
+
+/* Puts into 'b' a packet that flow_extract() would parse as having the given
+ * 'flow'.
+ *
+ * (This is useful only for testing, obviously, and the packet isn't really
+ * valid.  It hasn't got any checksums filled in, for one, and lots of fields
+ * are just zeroed.) */
+void
+flow_compose(struct ofpbuf *b, const struct flow *flow)
+{
+    eth_compose(b, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0);
+    if (flow->dl_type == htons(FLOW_DL_TYPE_NONE)) {
+        struct eth_header *eth = b->l2;
+        eth->eth_type = htons(b->size);
+        return;
+    }
+
+    if (flow->vlan_tci & htons(VLAN_CFI)) {
+        eth_set_vlan_tci(b, flow->vlan_tci & ~htons(VLAN_CFI));
+    }
+
+    if (flow->dl_type == htons(ETH_TYPE_IP)) {
+        struct ip_header *ip;
+
+        b->l3 = ip = ofpbuf_put_zeros(b, sizeof *ip);
+        ip->ip_ihl_ver = IP_IHL_VER(5, 4);
+        ip->ip_tos = flow->nw_tos;
+        ip->ip_proto = flow->nw_proto;
+        ip->ip_src = flow->nw_src;
+        ip->ip_dst = flow->nw_dst;
+
+        if (flow->nw_proto == IPPROTO_TCP) {
+            struct tcp_header *tcp;
+
+            b->l4 = tcp = ofpbuf_put_zeros(b, sizeof *tcp);
+            tcp->tcp_src = flow->tp_src;
+            tcp->tcp_dst = flow->tp_dst;
+        } else if (flow->nw_proto == IPPROTO_UDP) {
+            struct udp_header *udp;
+
+            b->l4 = udp = ofpbuf_put_zeros(b, sizeof *udp);
+            udp->udp_src = flow->tp_src;
+            udp->udp_dst = flow->tp_dst;
+        } else if (flow->nw_proto == IPPROTO_ICMP) {
+            struct icmp_header *icmp;
+
+            b->l4 = icmp = ofpbuf_put_zeros(b, sizeof *icmp);
+            icmp->icmp_type = ntohs(flow->tp_src);
+            icmp->icmp_code = ntohs(flow->tp_dst);
+        }
+    } else if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+        /* XXX */
+    } else if (flow->dl_type == htons(ETH_TYPE_ARP)) {
+        struct arp_eth_header *arp;
+
+        b->l3 = arp = ofpbuf_put_zeros(b, sizeof *arp);
+        arp->ar_hrd = htons(1);
+        arp->ar_pro = htons(ETH_TYPE_IP);
+        arp->ar_hln = ETH_ADDR_LEN;
+        arp->ar_pln = 4;
+        arp->ar_op = htons(flow->nw_proto);
+
+        if (flow->nw_proto == ARP_OP_REQUEST ||
+            flow->nw_proto == ARP_OP_REPLY) {
+            arp->ar_spa = flow->nw_src;
+            arp->ar_tpa = flow->nw_dst;
+            memcpy(arp->ar_sha, flow->arp_sha, ETH_ADDR_LEN);
+            memcpy(arp->ar_tha, flow->arp_tha, ETH_ADDR_LEN);
+        }
+    }
+}
diff --git a/lib/flow.h b/lib/flow.h
index d049e7e..1b3ee18 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -89,6 +89,8 @@ static inline int flow_compare(const struct flow *, const struct flow *);
 static inline bool flow_equal(const struct flow *, const struct flow *);
 static inline size_t flow_hash(const struct flow *, uint32_t basis);
 
+void flow_compose(struct ofpbuf *, const struct flow *);
+
 static inline int
 flow_compare(const struct flow *a, const struct flow *b)
 {
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 414c82b..3130da4 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -4074,8 +4074,8 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
     arg1 = strtok_r(NULL, " ", &save_ptr);
     arg2 = strtok_r(NULL, " ", &save_ptr);
     arg3 = strtok_r(NULL, "", &save_ptr); /* Get entire rest of line. */
-    if (dpname && arg1 && !arg2 && !arg3) {
-        /* ofproto/trace dpname flow */
+    if (dpname && arg1 && (!arg2 || !strcmp(arg2, "-packet")) && !arg3) {
+        /* ofproto/trace dpname flow [-packet] */
         int error;
 
         /* Convert string to ODP key. */
@@ -4092,6 +4092,12 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, const char *args_,
             unixctl_command_reply(conn, 501, "Invalid flow");
             goto exit;
         }
+
+        /* Generate a packet, if requested. */
+        if (arg2) {
+            packet = ofpbuf_new(0);
+            flow_compose(packet, &flow);
+        }
     } else if (dpname && arg1 && arg2 && arg3) {
         /* ofproto/trace dpname tun_id in_port packet */
         uint16_t in_port;
diff --git a/ofproto/ofproto-unixctl.man b/ofproto/ofproto-unixctl.man
index 06db7e0..3da4227 100644
--- a/ofproto/ofproto-unixctl.man
+++ b/ofproto/ofproto-unixctl.man
@@ -7,12 +7,12 @@ Lists the names of the running ofproto instances.  These are the names
 that may be used on \fBofproto/trace\fR.
 .
 .IP "\fBofproto/trace \fIswitch tun_id in_port packet\fR"
-Traces the path of an imaginary packet through \fIswitch\fR.  The
-arguments are:
+.IQ "\fBofproto/trace \fIswitch odp_flow \fB\-packet\fR"
+Traces the path of an imaginary packet through \fIswitch\fR.  Both
+forms require \fIswitch\fR, the switch on which the packet arrived
+(one of those listed by \fBofproto/list\fR).  The first form specifies
+a packet's contents explicitly:
 .RS
-.IP "\fIswitch\fR"
-The switch on which the packet arrived (one of those listed by
-\fBofproto/list\fR).
 .IP "\fItun_id\fR"
 The tunnel ID on which the packet arrived.  Use
 \fB0\fR if the packet did not arrive through a tunnel.
@@ -27,9 +27,18 @@ by hand, so the \fBovs\-pcap\fR(1) and \fBovs\-tcpundump\fR(1)
 utilities provide easier ways.
 .RE
 .IP
+The second form specifies the packet's contents implicitly:
+.RS
+.IP "\fIodp_flow\fR"
+A flow in the form printed by \fBovs\-dpctl\fR(8)'s \fBdump\-flows\fR
+command.  This is not an OpenFlow flow: besides other differences, it
+never contains wildcards.  \fB\*(PN\fR generates an arbitrary packet
+that has the specified \fIodp_flow\fR.
+.RE
+.IP
 \fB\*(PN\fR will respond with extensive information on how the packet
 would be handled if it were to be received.  The packet will not
-actually be sent.
+actually be sent, but side effects such as MAC learning will occur.
 .
 .IP "\fBofproto/trace \fIswitch odp_flow\fR"
 Traces the path of a packet in an imaginary flow through
@@ -46,7 +55,8 @@ never contains wildcards.
 .IP
 \fB\*(PN\fR will respond with extensive information on how a packet
 in \fIodp_flow\fR would be handled if it were received by
-\fIswitch\fR.  No packet will actually be sent.
+\fIswitch\fR.  No packet will actually be sent.  Some side effects may
+occur, but MAC learning in particular will not.
 .IP
 This form of \fBofproto/trace\fR cannot determine the complete set of
 datapath actions in some corner cases.  If the results say that this
-- 
1.7.4.4




More information about the dev mailing list