From fb892732bac6787c6fb943554f8000e26477dd85 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Mon, 9 Nov 2009 16:43:47 -0800 Subject: [PATCH] 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. --- include/openflow/openflow.h | 7 +++++-- lib/flow.c | 37 +++---------------------------------- lib/flow.h | 3 +-- lib/ofp-print.c | 9 +++++++-- lib/vconn.c | 11 +++++++++++ ofproto/ofproto.c | 5 +++-- 6 files changed, 30 insertions(+), 42 deletions(-) diff --git a/include/openflow/openflow.h b/include/openflow/openflow.h index 2847aedd..b655acf5 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 d8c28753..68a70478 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -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,42 +258,13 @@ 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) { 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 cb201099..b1292ce3 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 700f3c4f..97e37125 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 de407448..7aab8215 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -1425,6 +1425,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 18d3e029..00fb9b55 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -1860,7 +1860,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) | @@ -2635,7 +2636,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); -- 2.30.2