From: Justin Pettit Date: Tue, 10 Nov 2009 00:43:47 +0000 (-0800) Subject: ofproto: Add support for matching IP addresses in ARP header (OpenFlow 1.0) X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3579456f54092d7902cdd49054e7b028bd37cc23;p=sliver-openvswitch.git ofproto: Add support for matching IP addresses in ARP header (OpenFlow 1.0) The OpenFlow 1.0 specification supports matching the IP address and opcode in ARP messages. The datapath already supports this, so this commit merely exposes that through the OpenFlow module. NOTE: OVS at this point is not wire-compatible with OpenFlow 1.0 until the final commit in this OpenFlow 1.0 set. --- diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 2847aedd8..b655acf56 100644 --- a/include/openflow/openflow.h +++ b/include/openflow/openflow.h @@ -156,7 +156,9 @@ enum ofp_capabilities { OFPC_STP = 1 << 3, /* 802.1d spanning tree. */ OFPC_MULTI_PHY_TX = 1 << 4, /* Supports transmitting through multiple physical interfaces */ - OFPC_IP_REASM = 1 << 5 /* Can reassemble IP fragments. */ + OFPC_IP_REASM = 1 << 5, /* Can reassemble IP fragments. */ + OFPC_ARP_MATCH_IP = 1 << 7 /* Match IP addresses in ARP + pkts. */ }; /* Flags to indicate behavior of the physical port. These flags are @@ -511,7 +513,8 @@ struct ofp_match { uint8_t dl_vlan_pcp; /* Input VLAN priority. */ uint8_t pad1[1]; /* Align to 64-bits. */ uint16_t dl_type; /* Ethernet frame type. */ - uint8_t nw_proto; /* IP protocol. */ + uint8_t nw_proto; /* IP protocol or lower 8 bits of + ARP opcode. */ uint8_t pad2[3]; /* Align to 64-bits. */ uint32_t nw_src; /* IP source address. */ uint32_t nw_dst; /* IP destination address. */ diff --git a/lib/flow.c b/lib/flow.c index 45bd01ef4..68a704783 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -236,12 +236,10 @@ flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, stats->n_packets = 1; } -/* The Open vSwitch datapath supports matching on ARP payloads, which - * OpenFlow does not. This function is identical to 'flow_to_match', - * but does not hide the datapath's ability to match on ARP. */ +/* Extract 'flow' with 'wildcards' into the OpenFlow match structure + * 'match'. */ void -flow_to_ovs_match(const flow_t *flow, uint32_t wildcards, - struct ofp_match *match) +flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match) { match->wildcards = htonl(wildcards); match->in_port = htons(flow->in_port == ODPP_LOCAL ? OFPP_LOCAL @@ -260,26 +258,6 @@ flow_to_ovs_match(const flow_t *flow, uint32_t wildcards, memset(match->pad2, '\0', sizeof match->pad2); } -/* Extract 'flow' with 'wildcards' into the OpenFlow match structure - * 'match'. */ -void -flow_to_match(const flow_t *flow, uint32_t wildcards, struct ofp_match *match) -{ - flow_to_ovs_match(flow, wildcards, match); - - /* The datapath supports matching on an ARP's opcode and IP addresses, - * but OpenFlow does not. We wildcard and zero out the appropriate - * fields so that OpenFlow is unaware of our trickery. */ - if (flow->dl_type == htons(ETH_TYPE_ARP)) { - wildcards |= (OFPFW_NW_PROTO | OFPFW_NW_SRC_ALL | OFPFW_NW_DST_ALL); - match->nw_src = 0; - match->nw_dst = 0; - match->nw_proto = 0; - } - match->wildcards = htonl(wildcards); -} - - void flow_from_match(flow_t *flow, uint32_t *wildcards, const struct ofp_match *match) @@ -287,14 +265,6 @@ flow_from_match(flow_t *flow, uint32_t *wildcards, if (wildcards) { *wildcards = ntohl(match->wildcards); } - /* The datapath supports matching on an ARP's opcode and IP addresses, - * but OpenFlow does not. In case the controller hasn't, we need to - * set the appropriate wildcard bits so that we're externally - * OpenFlow-compliant. */ - if (match->dl_type == htons(ETH_TYPE_ARP)) { - *wildcards |= (OFPFW_NW_PROTO | OFPFW_NW_SRC_ALL | OFPFW_NW_DST_ALL); - } - flow->nw_src = match->nw_src; flow->nw_dst = match->nw_dst; flow->in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL diff --git a/lib/flow.h b/lib/flow.h index cb2010996..b1292ce35 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,7 +36,6 @@ int flow_extract(struct ofpbuf *, uint16_t in_port, flow_t *); void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet, struct odp_flow_stats *stats); void flow_to_match(const flow_t *, uint32_t wildcards, struct ofp_match *); -void flow_to_ovs_match(const flow_t *, uint32_t wildcards, struct ofp_match *); void flow_from_match(flow_t *, uint32_t *wildcards, const struct ofp_match *); char *flow_to_string(const flow_t *); void flow_format(struct ds *, const flow_t *); diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 25317f557..706cd58bf 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -690,8 +690,13 @@ ofp_match_to_string(const struct ofp_match *om, int verbosity) print_ip_netmask(&f, "nw_dst=", om->nw_dst, (w & OFPFW_NW_DST_MASK) >> OFPFW_NW_DST_SHIFT, verbosity); if (!skip_proto) { - print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity, - "%u", om->nw_proto); + if (om->dl_type == htons(ETH_TYPE_ARP)) { + print_wild(&f, "opcode=", w & OFPFW_NW_PROTO, verbosity, + "%u", om->nw_proto); + } else { + print_wild(&f, "nw_proto=", w & OFPFW_NW_PROTO, verbosity, + "%u", om->nw_proto); + } } if (om->nw_proto == IP_TYPE_ICMP) { print_wild(&f, "icmp_type=", w & OFPFW_ICMP_TYPE, verbosity, diff --git a/lib/vconn.c b/lib/vconn.c index 15ccfead1..546c60022 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -1398,6 +1398,17 @@ normalize_match(struct ofp_match *m) if (wc & OFPFW_NW_DST_MASK) { m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT); } + } else if (m->dl_type == htons(ETH_TYPE_ARP)) { + if (wc & OFPFW_NW_PROTO) { + m->nw_proto = 0; + } + if (wc & OFPFW_NW_SRC_MASK) { + m->nw_src &= flow_nw_bits_to_mask(wc, OFPFW_NW_SRC_SHIFT); + } + if (wc & OFPFW_NW_DST_MASK) { + m->nw_dst &= flow_nw_bits_to_mask(wc, OFPFW_NW_DST_SHIFT); + } + m->tp_src = m->tp_dst = 0; } else { /* Network and transport layer fields will always be extracted as * zeros, so we can do an exact-match on those values. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 325a11de9..ea97cb634 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1853,7 +1853,8 @@ handle_features_request(struct ofproto *p, struct ofconn *ofconn, osf->n_buffers = htonl(pktbuf_capacity()); osf->n_tables = 2; osf->capabilities = htonl(OFPC_FLOW_STATS | OFPC_TABLE_STATS | - OFPC_PORT_STATS | OFPC_MULTI_PHY_TX); + OFPC_PORT_STATS | OFPC_MULTI_PHY_TX | + OFPC_ARP_MATCH_IP); osf->actions = htonl((1u << OFPAT_OUTPUT) | (1u << OFPAT_SET_VLAN_VID) | (1u << OFPAT_SET_VLAN_PCP) | @@ -2628,7 +2629,7 @@ flow_stats_ds_cb(struct cls_rule *rule_, void *cbdata_) } query_stats(cbdata->ofproto, rule, &packet_count, &byte_count); - flow_to_ovs_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); + flow_to_match(&rule->cr.flow, rule->cr.wc.wildcards, &match); ds_put_format(results, "duration=%llds, ", (time_msec() - rule->created) / 1000);