summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/flow.c126
-rw-r--r--lib/flow.h4
-rw-r--r--lib/netdev-dummy.c15
3 files changed, 75 insertions, 70 deletions
diff --git a/lib/flow.c b/lib/flow.c
index f9d7c2a74..38ff29c8c 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -2692,56 +2692,66 @@ flow_set_mpls_lse(struct flow *flow, int idx, ovs_be32 lse)
flow->mpls_lse[idx] = lse;
}
+static void
+flow_compose_l7(struct dp_packet *p, const void *l7, size_t l7_len)
+{
+ if (l7_len) {
+ if (l7) {
+ dp_packet_put(p, l7, l7_len);
+ } else {
+ uint8_t *payload = dp_packet_put_uninit(p, l7_len);
+ for (size_t i = 0; i < l7_len; i++) {
+ payload[i] = i;
+ }
+ }
+ }
+}
+
static size_t
-flow_compose_l4(struct dp_packet *p, const struct flow *flow)
+flow_compose_l4(struct dp_packet *p, const struct flow *flow,
+ const void *l7, size_t l7_len)
{
- size_t l4_len = 0;
+ size_t orig_len = dp_packet_size(p);
if (!(flow->nw_frag & FLOW_NW_FRAG_ANY)
|| !(flow->nw_frag & FLOW_NW_FRAG_LATER)) {
if (flow->nw_proto == IPPROTO_TCP) {
- struct tcp_header *tcp;
-
- l4_len = sizeof *tcp;
- tcp = dp_packet_put_zeros(p, l4_len);
+ struct tcp_header *tcp = dp_packet_put_zeros(p, sizeof *tcp);
tcp->tcp_src = flow->tp_src;
tcp->tcp_dst = flow->tp_dst;
tcp->tcp_ctl = TCP_CTL(ntohs(flow->tcp_flags), 5);
+ if (!(flow->tcp_flags & htons(TCP_SYN | TCP_FIN | TCP_RST))) {
+ flow_compose_l7(p, l7, l7_len);
+ }
} else if (flow->nw_proto == IPPROTO_UDP) {
- struct udp_header *udp;
-
- l4_len = sizeof *udp;
- udp = dp_packet_put_zeros(p, l4_len);
+ struct udp_header *udp = dp_packet_put_zeros(p, sizeof *udp);
udp->udp_src = flow->tp_src;
udp->udp_dst = flow->tp_dst;
- udp->udp_len = htons(l4_len);
+ udp->udp_len = htons(sizeof *udp + l7_len);
+ flow_compose_l7(p, l7, l7_len);
} else if (flow->nw_proto == IPPROTO_SCTP) {
- struct sctp_header *sctp;
-
- l4_len = sizeof *sctp;
- sctp = dp_packet_put_zeros(p, l4_len);
+ struct sctp_header *sctp = dp_packet_put_zeros(p, sizeof *sctp);
sctp->sctp_src = flow->tp_src;
sctp->sctp_dst = flow->tp_dst;
+ /* XXX Someone should figure out what L7 data to include. */
} else if (flow->nw_proto == IPPROTO_ICMP) {
- struct icmp_header *icmp;
-
- l4_len = sizeof *icmp;
- icmp = dp_packet_put_zeros(p, l4_len);
+ struct icmp_header *icmp = dp_packet_put_zeros(p, sizeof *icmp);
icmp->icmp_type = ntohs(flow->tp_src);
icmp->icmp_code = ntohs(flow->tp_dst);
+ if ((icmp->icmp_type == ICMP4_ECHO_REQUEST ||
+ icmp->icmp_type == ICMP4_ECHO_REPLY)
+ && icmp->icmp_code == 0) {
+ flow_compose_l7(p, l7, l7_len);
+ } else {
+ /* XXX Add inner IP packet for e.g. destination unreachable? */
+ }
} else if (flow->nw_proto == IPPROTO_IGMP) {
- struct igmp_header *igmp;
-
- l4_len = sizeof *igmp;
- igmp = dp_packet_put_zeros(p, l4_len);
+ struct igmp_header *igmp = dp_packet_put_zeros(p, sizeof *igmp);
igmp->igmp_type = ntohs(flow->tp_src);
igmp->igmp_code = ntohs(flow->tp_dst);
put_16aligned_be32(&igmp->group, flow->igmp_group_ip4);
} else if (flow->nw_proto == IPPROTO_ICMPV6) {
- struct icmp6_hdr *icmp;
-
- l4_len = sizeof *icmp;
- icmp = dp_packet_put_zeros(p, l4_len);
+ struct icmp6_hdr *icmp = dp_packet_put_zeros(p, sizeof *icmp);
icmp->icmp6_type = ntohs(flow->tp_src);
icmp->icmp6_code = ntohs(flow->tp_dst);
@@ -2751,28 +2761,32 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow)
struct in6_addr *nd_target;
struct ovs_nd_lla_opt *lla_opt;
- l4_len += sizeof *nd_target;
nd_target = dp_packet_put_zeros(p, sizeof *nd_target);
*nd_target = flow->nd_target;
if (!eth_addr_is_zero(flow->arp_sha)) {
- l4_len += 8;
lla_opt = dp_packet_put_zeros(p, 8);
lla_opt->len = 1;
lla_opt->type = ND_OPT_SOURCE_LINKADDR;
lla_opt->mac = flow->arp_sha;
}
if (!eth_addr_is_zero(flow->arp_tha)) {
- l4_len += 8;
lla_opt = dp_packet_put_zeros(p, 8);
lla_opt->len = 1;
lla_opt->type = ND_OPT_TARGET_LINKADDR;
lla_opt->mac = flow->arp_tha;
}
+ } else if (icmp->icmp6_code == 0 &&
+ (icmp->icmp6_type == ICMP6_ECHO_REQUEST ||
+ icmp->icmp6_type == ICMP6_ECHO_REPLY)) {
+ flow_compose_l7(p, l7, l7_len);
+ } else {
+ /* XXX Add inner IP packet for e.g. destination unreachable? */
}
}
}
- return l4_len;
+
+ return dp_packet_size(p) - orig_len;
}
static void
@@ -2820,7 +2834,7 @@ flow_compose_l4_csum(struct dp_packet *p, const struct flow *flow,
* ip/udp lengths and l3/l4 checksums.
*
* 'size' needs to be larger then the current packet size. */
-static void
+void
packet_expand(struct dp_packet *p, const struct flow *flow, size_t size)
{
size_t extra_size;
@@ -2870,10 +2884,19 @@ packet_expand(struct dp_packet *p, const struct flow *flow, size_t size)
* (This is useful only for testing, obviously, and the packet isn't really
* valid. Lots of fields are just zeroed.)
*
- * The created packet has minimal packet size, just big enough to hold
- * the packet header fields. */
-static void
-flow_compose_minimal(struct dp_packet *p, const struct flow *flow)
+ * For packets whose protocols can encapsulate arbitrary L7 payloads, 'l7' and
+ * 'l7_len' determine that payload:
+ *
+ * - If 'l7_len' is zero, no payload is included.
+ *
+ * - If 'l7_len' is nonzero and 'l7' is null, an arbitrary payload 'l7_len'
+ * bytes long is included.
+ *
+ * - If 'l7_len' is nonzero and 'l7' is nonnull, the payload is copied
+ * from 'l7'. */
+void
+flow_compose(struct dp_packet *p, const struct flow *flow,
+ const void *l7, size_t l7_len)
{
uint32_t pseudo_hdr_csum;
size_t l4_len;
@@ -2913,7 +2936,7 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow)
dp_packet_set_l4(p, dp_packet_tail(p));
- l4_len = flow_compose_l4(p, flow);
+ l4_len = flow_compose_l4(p, flow, l7, l7_len);
ip = dp_packet_l3(p);
ip->ip_tot_len = htons(p->l4_ofs - p->l3_ofs + l4_len);
@@ -2936,7 +2959,7 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow)
dp_packet_set_l4(p, dp_packet_tail(p));
- l4_len = flow_compose_l4(p, flow);
+ l4_len = flow_compose_l4(p, flow, l7, l7_len);
nh = dp_packet_l3(p);
nh->ip6_plen = htons(l4_len);
@@ -2978,33 +3001,6 @@ flow_compose_minimal(struct dp_packet *p, const struct flow *flow)
}
}
}
-
-/* Puts into 'p' a Ethernet frame of size 'size' that flow_extract() would
- * parse as having the given 'flow'.
- *
- * When 'size' is zero, 'p' is a minimal size packet that only big enough
- * to contains all packet headers.
- *
- * When 'size' is larger than the minimal packet size, the packet will
- * be expended to 'size' with the payload set to zero.
- *
- * Return 'true' if the packet is successfully created. 'false' otherwise.
- * Note, when 'size' is set to zero, this function always returns true. */
-bool
-flow_compose(struct dp_packet *p, const struct flow *flow, size_t size)
-{
- flow_compose_minimal(p, flow);
-
- if (size && size < dp_packet_size(p)) {
- return false;
- }
-
- if (size > dp_packet_size(p)) {
- packet_expand(p, flow, size);
- }
-
- return true;
-}
/* Compressed flow. */
diff --git a/lib/flow.h b/lib/flow.h
index eb1e2bfc6..770a07a62 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -124,7 +124,9 @@ void flow_set_mpls_tc(struct flow *, int idx, uint8_t tc);
void flow_set_mpls_bos(struct flow *, int idx, uint8_t stack);
void flow_set_mpls_lse(struct flow *, int idx, ovs_be32 lse);
-bool flow_compose(struct dp_packet *, const struct flow *, size_t);
+void flow_compose(struct dp_packet *, const struct flow *,
+ const void *l7, size_t l7_len);
+void packet_expand(struct dp_packet *, const struct flow *, size_t size);
bool parse_ipv6_ext_hdrs(const void **datap, size_t *sizep, uint8_t *nw_proto,
uint8_t *nw_frag);
diff --git a/lib/netdev-dummy.c b/lib/netdev-dummy.c
index 4246af3b9..0d05759e4 100644
--- a/lib/netdev-dummy.c
+++ b/lib/netdev-dummy.c
@@ -1520,10 +1520,17 @@ eth_from_flow(const char *s, size_t packet_size)
}
packet = dp_packet_new(0);
- if (!flow_compose(packet, &flow, packet_size)) {
- dp_packet_delete(packet);
- packet = NULL;
- };
+ if (packet_size) {
+ flow_compose(packet, &flow, NULL, 0);
+ if (dp_packet_size(packet) < packet_size) {
+ packet_expand(packet, &flow, packet_size);
+ } else if (dp_packet_size(packet) > packet_size){
+ dp_packet_delete(packet);
+ packet = NULL;
+ }
+ } else {
+ flow_compose(packet, &flow, NULL, 64);
+ }
ofpbuf_uninit(&odp_key);
return packet;