From 8b3b8dd1a5a1a8ba3b7e62798ff70cb8f9fc7659 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Thu, 8 Sep 2011 14:32:13 -0700 Subject: [PATCH] ofproto-dpif: Add -generate option to ofproto/trace command. --- 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 460771ccb..916d41c54 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_push_vlan(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 d049e7e61..1b3ee1817 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 dfdaaa299..7174748b5 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4099,8 +4099,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, "-generate")) && !arg3) { + /* ofproto/trace dpname flow [-generate] */ int error; /* Convert string to datapath key. */ @@ -4117,6 +4117,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 06db7e04d..2cf7bfaa8 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\-generate\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 -- 2.43.0