In order to present a concrete example of extending the switch functionality (within the confines of OpenFlow 1.1), this page shows briefly how IPv6 support could be added to the current implementation.
To provide the minimal IPv6 functionality (similar to the current IPv4 one), the switch must be able to match on various IPv6 header fields, and execute actions on those fields.
OpenFlow 1.1 uses rigid match structures; and only allows the definition of new structures, but no extension of existing standard match structure. So for IPv6 a new match structure must be defined. This should be pretty similar to the standard match structure, only the IPv4 fields must be replaced with IPv6 ones, including masks and wildcards. If cross-layer matching is required (e.g. matching on IPv6 address and TCP port), the rest of the protocol fields must be duplicated; otherwise the transport layers can be omitted. It would be also possible to support both IPv4 and IPv6 (similar to how UDP and TCP are both supported in the standard match) in the new match structure, and thus using only that; however I think it is better to support only IPv6 in the new match structure, and use the standard match for IPv4 processing.
Some of the standard actions can be reused for IPv6 processing -- such as TTL decrease --, but for some fields new actions must be defined; either because of the increased field size (IPv4 addresses vs IPv6 addresses), or because those did not exist in IPv4 (e.g. flow label). The definition of these actions should be straightforward based on the standard ones.
The wire format representation of both the new match structure and the actions should follow the wire format: the appropriate headers must be reused with newly defined subtype constants; otherwise the wire format can be arbitrary. Similarly the internal implementation must reuse the internal representation headers (namely ofl_match_header and ofl_action_experimenter), similar to the standard ones; otherwise the format can be arbitrarily defined.
Additionally the experimenter callbacks must be implemented, which will be used by oflib, whenever it encounters such experimenter match structures and actions. In this example the ofl_exp_match and ofl_exp_act callback groups must be implemented. The oflib functions for processing the standard entities can serve as guidance for the implementation.
Extending the datapath
As control channel processing mostly relies on entity headers only, IPv6 extension does not affect the code. Some implementation is required, but that will be addressed along with the datapath implementations. Namely, flow_mod processing relies on comparisons (overlapping, strict, etc.) of match structures, and packet_out processing requires the use of new actions. These will be addressed in Matching and Packet processing.
Also while the syntax check of actions are done in the oflib, in theory they might need to go through semantic checking. This is probably not the case, as is not for IPv4 either, but would it be so, it should be implemented by extending the dp_actions_validate function in the dp_actions.c file. This function only checks whether the referred ports and groups are available at the moment.
While the control channel needs minimal modifications, the datapath processing part have to be extended in multiple locations.
When a datapath packet is received on a switch port, or in a packet_out message, it is converted into a packet structure; seepacket.c. Before the switch can match the packet against flow entries, the packet must be preprocessed, where match fields are extracted. This is done in so called handlers: a handler is responsible for extracting fields of a given match type. Naturally in the original implementation only a single handler (packet_handle_std) exists, which extracts standard match fields from the packet. This handler is basically an implementation of the parsing flow chart, which is provided in the specification (as of 1.1.0 implemented).
For IPv6 support a handler very similar to the standard one must be created. Only IPv4 parsing should be replaced with IPv6 parsing functionality. Additionally this new handler must also be made part of the packet structure similar to the standard handler.
While a handler might be lazy evaluated, it should be evaluated before matching begins, because of other constraints defined by the OpenFlow protocol. Namely, the packet should be checked for TTL validity before any further processing. This check is currently implemented in pipeline_process_packet (pipeline.c), which should be extended with similar check should be done on the IPv6 parsed packet. Considering performance, it should be theoretically possible to process the packet in one stage for the two handlers, but such (premature) optimizations are not considered here.
At the moment each flow table is represented as a single list, where flow entries are ordered by their prioirities. Flow table processing is implemented in flow_table_lookup (flow_table.c). This function goes through the flow entries of the table one by one, and for each entry it checks whether the appropriate handler matches the given flow entry match structure. At this point a case for the new IPv6 match structure should be added. Additionally the code that checks whether the given IPv6 match structure of the flow entry matches that of the handler (extracted from the packet) must be implemented. For the standard match structure this can be found in match_std.c. Note that this is the functionality which is also used by flow_mod processing, when checking for overlaps and strict matches.
Actions of write instructions, action sets and packet_out messages are executed in the dp_execute_action function (dp_actions.c). For convenience this function calls into dp_exp_action (dp_exp.c) stub function; this is the place where experimenter actions should be implemented. Each action should update the appropriate protocol field in the packet itself - which should be straightforward - and should also update the handlers, so that their match structures remain up-to-date. If the update is straightforward, it can update the match structure; otherwise it can simply revalidate the handler by invoking a complete reprocessing of the packet.