LCOV - code coverage report
Current view: top level - net - switchofp.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 2727 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 147 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: switchofp.c,v 1.71 2018/08/21 16:40:23 akoshibe Exp $ */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2016 Kazuya GODA <goda@openbsd.org>
       5             :  * Copyright (c) 2015, 2016 YASUOKA Masahiko <yasuoka@openbsd.org>
       6             :  * Copyright (c) 2015, 2016 Reyk Floeter <reyk@openbsd.org>
       7             :  *
       8             :  * Permission to use, copy, modify, and distribute this software for any
       9             :  * purpose with or without fee is hereby granted, provided that the above
      10             :  * copyright notice and this permission notice appear in all copies.
      11             :  *
      12             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      13             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      14             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      15             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      16             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      17             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      18             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      19             :  */
      20             : 
      21             : #include "bpfilter.h"
      22             : 
      23             : #include <sys/param.h>
      24             : #include <sys/systm.h>
      25             : #include <sys/errno.h>
      26             : #include <sys/mbuf.h>
      27             : #include <sys/socket.h>
      28             : #include <sys/sockio.h>
      29             : #include <sys/selinfo.h>
      30             : #include <sys/stdint.h>
      31             : #include <sys/time.h>
      32             : #include <sys/pool.h>
      33             : #include <sys/syslog.h>
      34             : 
      35             : #include <net/if.h>
      36             : #include <netinet/in.h>
      37             : #include <netinet/ip.h>
      38             : #include <netinet/ip6.h>
      39             : #include <netinet/udp.h>
      40             : #include <netinet/tcp.h>
      41             : #include <netinet/ip_icmp.h>
      42             : #include <netinet/icmp6.h>
      43             : #include <netinet6/nd6.h>
      44             : #include <netinet/if_ether.h>
      45             : #include <net/if_bridge.h>
      46             : #include <net/if_switch.h>
      47             : #include <net/if_vlan_var.h>
      48             : #include <net/ofp.h>
      49             : 
      50             : #if NBPFILTER > 0
      51             : #include <net/bpf.h>
      52             : #endif
      53             : 
      54             : /*
      55             :  * Per-frame debugging can be done at any time using the BPF
      56             :  * hook of DLT_OPENFLOW (eg. tcpdump -y openflow -i switch0)
      57             :  */
      58             : #ifdef DEBUG
      59             : #define DPRINTF(__sc, ...)                              \
      60             : do {                                                    \
      61             :         struct switch_softc *_sc = __sc;                \
      62             :         log(LOG_DEBUG, "%s: ", _sc->sc_if.if_xname);       \
      63             :         addlog(__VA_ARGS__);                            \
      64             : } while(/*CONSTCOND*/0)
      65             : #else
      66             : #define DPRINTF(__sc, ...)      do {} while(0)
      67             : #endif
      68             : 
      69             : struct swofp_flow_entry {
      70             :         uint64_t                                 swfe_cookie;
      71             :         uint16_t                                 swfe_priority;
      72             :         uint8_t                                  swfe_table_id;
      73             :         struct ofp_match                        *swfe_match;
      74             :         LIST_ENTRY(swofp_flow_entry)             swfe_next;
      75             :         uint64_t                                 swfe_packet_cnt;
      76             :         uint64_t                                 swfe_byte_cnt;
      77             :         struct ofp_instruction_goto_table       *swfe_goto_table;
      78             :         struct ofp_instruction_write_metadata   *swfe_write_metadata;
      79             :         struct ofp_instruction_actions          *swfe_write_actions;
      80             :         struct ofp_instruction_actions          *swfe_apply_actions;
      81             :         struct ofp_instruction_actions          *swfe_clear_actions;
      82             :         struct ofp_instruction_meter            *swfe_meter;
      83             :         struct ofp_instruction_experimenter     *swfe_experimenter;
      84             :         struct timespec                          swfe_installed_time;
      85             :         struct timespec                          swfe_idle_time;
      86             :         uint16_t                                 swfe_idle_timeout;
      87             :         uint16_t                                 swfe_hard_timeout;
      88             :         uint16_t                                 swfe_flags;
      89             :         int                                      swfe_tablemiss;
      90             : };
      91             : 
      92             : struct swofp_flow_table {
      93             :         uint32_t                         swft_table_id;
      94             :         TAILQ_ENTRY(swofp_flow_table)    swft_table_next;
      95             :         uint64_t                         swft_lookup_count;
      96             :         uint64_t                         swft_matched_count;
      97             :         LIST_HEAD(, swofp_flow_entry)    swft_flow_list;
      98             :         uint32_t                         swft_flow_num;
      99             : };
     100             : 
     101             : struct swofp_group_entry {
     102             :         uint32_t                         swge_group_id;
     103             :         LIST_ENTRY(swofp_group_entry)    swge_next;
     104             :         uint64_t                         swge_packet_count;
     105             :         uint64_t                         swge_byte_count;
     106             :         uint32_t                         swge_ref_count;
     107             :         uint8_t                          swge_type;
     108             :         uint32_t                         swge_buckets_len;
     109             :         struct ofp_bucket               *swge_buckets;
     110             :         struct ofp_bucket_counter       *swge_bucket_counter; /* XXX */
     111             :         struct timespec                  swge_installed_time;
     112             : };
     113             : 
     114             : struct swofp_action_set {
     115             :         uint16_t                         swas_type;
     116             :         struct ofp_action_header        *swas_action;
     117             : };
     118             : 
     119             : /* Same as total number of OFP_ACTION_ */
     120             : #define SWOFP_ACTION_SET_MAX            18
     121             : struct swofp_pipeline_desc {
     122             :         uint32_t                         swpld_table_id;
     123             :         uint64_t                         swpld_cookie;
     124             :         uint64_t                         swpld_metadata;
     125             :         struct switch_flow_classify     *swpld_swfcl;
     126             :         struct switch_flow_classify      swpld_pre_swfcl;
     127             :         struct switch_fwdp_queue         swpld_fwdp_q;
     128             :         struct swofp_action_set          swpld_action_set[SWOFP_ACTION_SET_MAX];
     129             :         struct ofp_action_header        *swpld_set_fields[OFP_XM_T_MAX];
     130             :         int                              swpld_tablemiss;
     131             : };
     132             : 
     133             : struct swofp_ofs {
     134             :         /* There are parameters by OpenFlow */
     135             :         uint32_t                         swofs_xidnxt;
     136             :         uint64_t                         swofs_datapath_id;
     137             :         struct ofp_switch_config         swofs_switch_config;
     138             :         struct timeout                   swofs_flow_timeout;
     139             :         uint32_t                         swofs_flow_max_entry;
     140             :         TAILQ_HEAD(, swofp_flow_table)   swofs_table_list;
     141             :         uint32_t                         swofs_group_max_table;
     142             :         int                              swofs_group_table_num;
     143             :         LIST_HEAD(, swofp_group_entry)   swofs_group_table;
     144             :         int                             (*swofp_cp_init)(struct switch_softc *);
     145             : };
     146             : 
     147             : struct swofp_mpmsg {
     148             :         struct mbuf             *swmp_hdr;
     149             :         struct mbuf_list         swmp_body;
     150             : };
     151             : #define SWOFP_MPMSG_MAX         0xffef
     152             : 
     153             : typedef int     (*ofp_msg_handler)(struct switch_softc *, struct mbuf *);
     154             : 
     155             : void     swofp_forward_ofs(struct switch_softc *, struct switch_flow_classify *,
     156             :             struct mbuf *);
     157             : 
     158             : int      swofp_input(struct switch_softc *, struct mbuf *);
     159             : int      swofp_output(struct switch_softc *, struct mbuf *);
     160             : void     swofp_timer(void *);
     161             : 
     162             : struct ofp_oxm_class
     163             :         *swofp_lookup_oxm_handler(struct ofp_ox_match *);
     164             : ofp_msg_handler
     165             :         swofp_lookup_msg_handler(uint8_t);
     166             : ofp_msg_handler
     167             :         swofp_lookup_mpmsg_handler(uint16_t);
     168             : struct ofp_action_handler
     169             :         *swofp_lookup_action_handler(uint16_t);
     170             : ofp_msg_handler
     171             :         *swofp_flow_mod_lookup_handler(uint8_t);
     172             : struct swofp_pipeline_desc
     173             :         *swofp_pipeline_desc_create(struct switch_flow_classify *);
     174             : void     swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *);
     175             : int      swofp_flow_match_by_swfcl(struct ofp_match *,
     176             :             struct switch_flow_classify *);
     177             : struct swofp_flow_entry
     178             :         *swofp_flow_lookup(struct swofp_flow_table *,
     179             :             struct switch_flow_classify *);
     180             : 
     181             : /*
     182             :  * Flow table
     183             :  */
     184             : struct swofp_flow_table
     185             :         *swofp_flow_table_lookup(struct switch_softc *, uint16_t);
     186             : struct swofp_flow_table
     187             :         *swofp_flow_table_add(struct switch_softc *, uint16_t);
     188             : int      swofp_flow_table_delete(struct switch_softc *, uint16_t);
     189             : void     swofp_flow_table_delete_all(struct switch_softc *);
     190             : void     swofp_flow_delete_on_table_by_group(struct switch_softc *,
     191             :             struct swofp_flow_table *, uint32_t);
     192             : void     swofp_flow_delete_on_table(struct switch_softc *,
     193             :             struct swofp_flow_table *, struct ofp_match *, uint16_t,
     194             :             uint64_t, uint64_t cookie_mask, uint32_t,
     195             :             uint32_t, int);
     196             : 
     197             : /*
     198             :  * Group table
     199             :  */
     200             : struct swofp_group_entry
     201             :         *swofp_group_entry_lookup(struct switch_softc *, uint32_t);
     202             : int      swofp_group_entry_add(struct switch_softc *,
     203             :             struct swofp_group_entry *);
     204             : int      swofp_group_entry_delete(struct switch_softc *,
     205             :             struct swofp_group_entry *);
     206             : int      swofp_group_entry_delete_all(struct switch_softc *);
     207             : int      swofp_validate_buckets(struct switch_softc *, struct mbuf *, uint8_t,
     208             :             uint16_t *, uint16_t *);
     209             : 
     210             : /*
     211             :  * Flow entry
     212             :  */
     213             : int      swofp_flow_entry_put_instructions(struct switch_softc *,
     214             :             struct mbuf *, struct swofp_flow_entry *, uint16_t *, uint16_t *);
     215             : void     swofp_flow_entry_table_free(struct ofp_instruction **);
     216             : void     swofp_flow_entry_instruction_free(struct swofp_flow_entry *);
     217             : void     swofp_flow_entry_free(struct swofp_flow_entry **);
     218             : void     swofp_flow_entry_add(struct switch_softc *, struct swofp_flow_table *,
     219             :             struct swofp_flow_entry *);
     220             : void     swofp_flow_entry_delete(struct switch_softc *,
     221             :             struct swofp_flow_table *, struct swofp_flow_entry *, uint8_t);
     222             : int      swofp_flow_mod_cmd_common_modify(struct switch_softc *,
     223             :             struct mbuf *, int );
     224             : int      swofp_flow_cmp_non_strict(struct swofp_flow_entry *,
     225             :             struct ofp_match *);
     226             : int      swofp_flow_cmp_strict(struct swofp_flow_entry *, struct ofp_match *,
     227             :             uint32_t);
     228             : int      swofp_flow_cmp_common(struct swofp_flow_entry *,
     229             :             struct ofp_match *, int);
     230             : struct swofp_flow_entry
     231             :         *swofp_flow_search_by_table(struct swofp_flow_table *,
     232             :             struct ofp_match *, uint16_t);
     233             : int      swofp_flow_has_group(struct ofp_instruction_actions *, uint32_t);
     234             : int      swofp_flow_filter_out_port(struct ofp_instruction_actions *,
     235             :             uint32_t);
     236             : int      swofp_flow_filter(struct swofp_flow_entry *, uint64_t, uint64_t,
     237             :             uint32_t, uint32_t);
     238             : void     swofp_flow_timeout(struct switch_softc *);
     239             : int      swofp_validate_oxm(struct ofp_ox_match *, uint16_t *);
     240             : int      swofp_validate_flow_match(struct ofp_match *, uint16_t *);
     241             : int      swofp_validate_flow_instruction(struct switch_softc *,
     242             :             struct ofp_instruction *, size_t, uint16_t *, uint16_t *);
     243             : int      swofp_validate_action(struct switch_softc *sc,
     244             :             struct ofp_action_header *, size_t, uint16_t *);
     245             : 
     246             : /*
     247             :  * OpenFlow protocol compare oxm
     248             :  */
     249             : int     swofp_ox_cmp_data(struct ofp_ox_match *,
     250             :             struct ofp_ox_match *, int);
     251             : int     swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *,
     252             :             struct ofp_ox_match *, int);
     253             : int     swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *,
     254             :             struct ofp_ox_match *, int);
     255             : int     swofp_ox_cmp_vlan_vid(struct ofp_ox_match *,
     256             :             struct ofp_ox_match *, int);
     257             : int     swofp_ox_cmp_ether_addr(struct ofp_ox_match *,
     258             :             struct ofp_ox_match *, int);
     259             : /*
     260             :  * OpenFlow protocol match field handlers
     261             :  */
     262             : int      swofp_ox_match_ether_addr(struct switch_flow_classify *,
     263             :             struct ofp_ox_match *);
     264             : int      swofp_ox_match_vlan_vid(struct switch_flow_classify *,
     265             :             struct ofp_ox_match *);
     266             : int      swofp_ox_match_ipv6_addr(struct switch_flow_classify *,
     267             :             struct ofp_ox_match *);
     268             : int      swofp_ox_match_ipv4_addr(struct switch_flow_classify *,
     269             :             struct ofp_ox_match *);
     270             : int      swofp_ox_match_uint8(struct switch_flow_classify *,
     271             :             struct ofp_ox_match *);
     272             : int      swofp_ox_match_uint16(struct switch_flow_classify *,
     273             :             struct ofp_ox_match *);
     274             : int      swofp_ox_match_uint32(struct switch_flow_classify *,
     275             :             struct ofp_ox_match *);
     276             : int      swofp_ox_match_uint64(struct switch_flow_classify *,
     277             :             struct ofp_ox_match *);
     278             : 
     279             : void     swofp_ox_match_put_start(struct ofp_match *);
     280             : int      swofp_ox_match_put_end(struct ofp_match *);
     281             : int      swofp_ox_match_put_uint32(struct ofp_match *, uint8_t, uint32_t);
     282             : int      swofp_ox_match_put_uint64(struct ofp_match *, uint8_t, uint64_t);
     283             : int      swofp_nx_match_put(struct ofp_match *, uint8_t, int, caddr_t);
     284             : 
     285             : /*
     286             :  * OpenFlow protocol push/pop tag action handlers
     287             :  */
     288             : struct mbuf
     289             :         *swofp_action_push_vlan(struct switch_softc *, struct mbuf *,
     290             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     291             : struct mbuf
     292             :         *swofp_action_pop_vlan(struct switch_softc *, struct mbuf *,
     293             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     294             : struct mbuf
     295             :         *swofp_expand_8021q_tag(struct mbuf *);
     296             : 
     297             : /*
     298             :  * OpenFlow protocol set field action handlers
     299             :  */
     300             : struct mbuf
     301             :         *swofp_apply_set_field_udp(struct mbuf *, int,
     302             :             struct switch_flow_classify *, struct switch_flow_classify *);
     303             : struct mbuf
     304             :         *swofp_apply_set_field_tcp(struct mbuf *, int,
     305             :             struct switch_flow_classify *, struct switch_flow_classify *);
     306             : struct mbuf
     307             :         *swofp_apply_set_field_nd6(struct mbuf *, int,
     308             :             struct switch_flow_classify *, struct switch_flow_classify *);
     309             : struct mbuf
     310             :         *swofp_apply_set_field_icmpv6(struct mbuf *m, int,
     311             :             struct switch_flow_classify *, struct switch_flow_classify *);
     312             : struct mbuf
     313             :         *swofp_apply_set_field_icmpv4(struct mbuf *, int,
     314             :             struct switch_flow_classify *, struct switch_flow_classify *);
     315             : struct mbuf
     316             :         *swofp_apply_set_field_ipv6(struct mbuf *, int,
     317             :             struct switch_flow_classify *, struct switch_flow_classify *);
     318             : struct mbuf
     319             :         *swofp_apply_set_field_ipv4(struct mbuf *, int,
     320             :             struct switch_flow_classify *, struct switch_flow_classify *);
     321             : struct mbuf
     322             :         *swofp_apply_set_field_arp(struct mbuf *, int,
     323             :             struct switch_flow_classify *, struct switch_flow_classify *);
     324             : struct mbuf
     325             :         *swofp_apply_set_field_ether(struct mbuf *, int,
     326             :             struct switch_flow_classify *, struct switch_flow_classify *);
     327             : struct mbuf
     328             :         *swofp_apply_set_field_tunnel(struct mbuf *, int,
     329             :             struct switch_flow_classify *, struct switch_flow_classify *);
     330             : struct mbuf
     331             :         *swofp_apply_set_field(struct mbuf *, struct swofp_pipeline_desc *);
     332             : int      swofp_ox_set_vlan_vid(struct switch_flow_classify *,
     333             :             struct ofp_ox_match *);
     334             : int      swofp_ox_set_uint8(struct switch_flow_classify *,
     335             :             struct ofp_ox_match *);
     336             : int      swofp_ox_set_uint16(struct switch_flow_classify *,
     337             :             struct ofp_ox_match *);
     338             : int      swofp_ox_set_uint32(struct switch_flow_classify *,
     339             :             struct ofp_ox_match *);
     340             : int      swofp_ox_set_uint64(struct switch_flow_classify *,
     341             :             struct ofp_ox_match *);
     342             : int      swofp_ox_set_ether_addr(struct switch_flow_classify *,
     343             :             struct ofp_ox_match *);
     344             : int      swofp_ox_set_ipv4_addr(struct switch_flow_classify *,
     345             :             struct ofp_ox_match *);
     346             : int      swofp_ox_set_ipv6_addr(struct switch_flow_classify *,
     347             :             struct ofp_ox_match *);
     348             : 
     349             : /*
     350             :  * OpenFlow protocol execute action handlers
     351             :  */
     352             : int      swofp_action_output_controller(struct switch_softc *, struct mbuf *,
     353             :             struct swofp_pipeline_desc *, uint16_t, uint8_t);
     354             : struct mbuf
     355             :         *swofp_action_output(struct switch_softc *, struct mbuf *,
     356             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     357             : struct mbuf
     358             :         *swofp_action_group_all(struct switch_softc *, struct mbuf *,
     359             :             struct swofp_pipeline_desc *, struct swofp_group_entry *);
     360             : struct mbuf
     361             :         *swofp_action_group(struct switch_softc *, struct mbuf *,
     362             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     363             : struct mbuf
     364             :         *swofp_action_set_field(struct switch_softc *, struct mbuf *,
     365             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     366             : struct mbuf
     367             :         *swofp_execute_action(struct switch_softc *, struct mbuf *,
     368             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     369             : struct mbuf
     370             :         *swofp_execute_action_set_field(struct switch_softc *, struct mbuf *,
     371             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     372             : struct mbuf
     373             :         *swofp_execute_action_set(struct switch_softc *, struct mbuf *,
     374             :             struct swofp_pipeline_desc *);
     375             : struct mbuf
     376             :         *swofp_apply_actions(struct switch_softc *, struct mbuf *,
     377             :             struct swofp_pipeline_desc *, struct ofp_instruction_actions *);
     378             : struct swofp_action_set
     379             :         *swofp_lookup_action_set(struct swofp_pipeline_desc *, uint16_t);
     380             : void     swofp_write_actions_set_field(struct swofp_action_set *,
     381             :             struct ofp_action_header *);
     382             : int      swofp_write_actions(struct ofp_instruction_actions *,
     383             :             struct swofp_pipeline_desc *);
     384             : void     swofp_clear_actions_set_field(struct swofp_action_set *,
     385             :             struct ofp_action_header *);
     386             : int      swofp_clear_actions(struct ofp_instruction_actions *,
     387             :             struct swofp_pipeline_desc *);
     388             : void     swofp_write_metadata(struct ofp_instruction_write_metadata *,
     389             :             struct swofp_pipeline_desc *);
     390             : 
     391             : /*
     392             :  * OpenFlow protocol message handlers
     393             :  */
     394             : void     swofp_send_hello(struct switch_softc *);
     395             : int      swofp_recv_hello(struct switch_softc *, struct mbuf *);
     396             : int      swofp_send_echo(struct switch_softc *, struct mbuf *);
     397             : int      swofp_recv_echo(struct switch_softc *, struct mbuf *);
     398             : void     swofp_send_error(struct switch_softc *, struct mbuf *,
     399             :             uint16_t, uint16_t);
     400             : int      swofp_recv_features_req(struct switch_softc *, struct mbuf *);
     401             : int      swofp_recv_config_req(struct switch_softc *, struct mbuf *);
     402             : int      swofp_recv_set_config(struct switch_softc *, struct mbuf *);
     403             : int      swofp_send_flow_removed(struct switch_softc *,
     404             :             struct swofp_flow_entry *, uint8_t);
     405             : int      swofp_recv_packet_out(struct switch_softc *, struct mbuf *);
     406             : int      swofp_flow_mod_cmd_add(struct switch_softc *, struct mbuf *);
     407             : int      swofp_flow_mod_cmd_common_modify(struct switch_softc *,
     408             :             struct mbuf *, int);
     409             : int      swofp_flow_mod_cmd_modify(struct switch_softc *, struct mbuf *);
     410             : int      swofp_flow_mod_cmd_modify_strict(struct switch_softc *, struct mbuf *);
     411             : int      swofp_flow_mod_cmd_common_delete(struct switch_softc *,
     412             :             struct mbuf *, int);
     413             : int      swofp_flow_mod_cmd_delete(struct switch_softc *, struct mbuf *);
     414             : int      swofp_flow_mod_cmd_delete_strict(struct switch_softc *, struct mbuf *);
     415             : int      swofp_flow_mod(struct switch_softc *, struct mbuf *);
     416             : int      swofp_group_mod_add(struct switch_softc *, struct mbuf *);
     417             : int      swofp_group_mod_modify(struct switch_softc *, struct mbuf *);
     418             : int      swofp_group_mod_delete(struct switch_softc *, struct mbuf *);
     419             : int      swofp_group_mod(struct switch_softc *, struct mbuf *);
     420             : int      swofp_multipart_req(struct switch_softc *, struct mbuf *);
     421             : int      swofp_barrier_req(struct switch_softc *, struct mbuf *);
     422             : void     swofp_barrier_reply(struct switch_softc *, struct mbuf *);
     423             : 
     424             : /*
     425             :  * OpenFlow protocol multipart message handlers
     426             :  */
     427             : int     swofp_mpmsg_reply_create(struct ofp_multipart *, struct swofp_mpmsg *);
     428             : int     swofp_mpmsg_put(struct swofp_mpmsg *, caddr_t, size_t);
     429             : int     swofp_mpmsg_m_put(struct swofp_mpmsg *, struct mbuf *);
     430             : void    swofp_mpmsg_destroy(struct swofp_mpmsg *);
     431             : int     swofp_multipart_reply(struct switch_softc *, struct swofp_mpmsg *);
     432             : 
     433             : int     swofp_put_flow(struct mbuf *, struct swofp_flow_table *,
     434             :             struct swofp_flow_entry *);
     435             : int     swofp_put_flows_from_table(struct swofp_mpmsg *,
     436             :             struct swofp_flow_table *, struct ofp_flow_stats_request *);
     437             : void    swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *,
     438             :             struct swofp_flow_table *, struct ofp_aggregate_stats_request *);
     439             : int     swofp_table_features_put_oxm(struct mbuf *, int *, uint16_t);
     440             : int     swofp_table_features_put_actions(struct mbuf *, int *, uint16_t);
     441             : int     swofp_table_features_put_instruction(struct mbuf *, int *, uint16_t);
     442             : 
     443             : int     swofp_mp_recv_desc(struct switch_softc *, struct mbuf *);
     444             : int     swofp_mp_recv_flow(struct switch_softc *, struct mbuf *);
     445             : int     swofp_mp_recv_aggregate_flow_stat(struct switch_softc *, struct mbuf *);
     446             : int     swofp_mp_recv_table_stats(struct switch_softc *, struct mbuf *);
     447             : int     swofp_mp_recv_table_features(struct switch_softc *, struct mbuf *);
     448             : int     swofp_mp_recv_port_stats(struct switch_softc *, struct mbuf *);
     449             : int     swofp_mp_recv_port_desc(struct switch_softc *, struct mbuf *);
     450             : int     swofp_mp_recv_group_desc(struct switch_softc *, struct mbuf *);
     451             : 
     452             : #define OFP_ALIGNMENT 8
     453             : /*
     454             :  * OXM (OpenFlow Extensible Match) structures appear in ofp_match structure
     455             :  * and ofp_instruction_{apply|write}_action structure.
     456             :  */
     457             : #define OFP_OXM_FOREACH(hdr, len, curr)                                 \
     458             : for ((curr) = (struct ofp_ox_match *)((caddr_t)(hdr) + sizeof(*hdr));   \
     459             :      (caddr_t)(curr) < ((caddr_t)(hdr) + (len));                     \
     460             :      (curr) = (struct ofp_ox_match *)((caddr_t)(curr) +                 \
     461             :          (curr)->oxm_length + sizeof(*curr)))
     462             : 
     463             : #define OFP_OXM_TERMINATED(hdr, len, curr)              \
     464             :         (((caddr_t)(hdr) + (len)) <= (caddr_t)(curr))
     465             : 
     466             : 
     467             : #define OFP_ACTION_FOREACH(head, len, curr)                             \
     468             : /* struct ofp_action_header head, curr */                               \
     469             : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (len));               \
     470             :     (curr) = (struct ofp_action_header *)((caddr_t)curr +               \
     471             :         ntohs((curr)->ah_len)))
     472             : 
     473             : /*
     474             :  * Get instruction offset in ofp_flow_mod
     475             :  */
     476             : #define OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm)                \
     477             :         (offsetof(struct ofp_flow_mod, fm_match) +              \
     478             :             OFP_ALIGN(ntohs((ofm)->fm_match.om_length)))
     479             : 
     480             : /*
     481             :  * Instructions "FOREACH" in ofp_flow_mod. You can get header using
     482             :  * OFP_FLOW_MOD_MSG_INSTRUCTION_PTR macro
     483             :  */
     484             : #define OFP_FLOW_MOD_INSTRUCTON_FOREACH(hadr, end, curr)                        \
     485             : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end));                       \
     486             :      (curr) = (struct ofp_instruction *)((caddr_t)(curr) + (curr)->i_len))
     487             : 
     488             : 
     489             : #define OFP_I_ACTIONS_FOREACH(head, curr)                                       \
     490             : /* struct ofp_match head, struct ofp_ox_match curr */                           \
     491             : for ((curr) = (struct ofp_action_header *)((caddr_t)head + sizeof(*head));      \
     492             :     (caddr_t)curr < ((caddr_t)head + ntohs((head)->ia_len));                      \
     493             :     (curr) = (struct ofp_action_header *)((caddr_t)curr +                       \
     494             :          ntohs((curr)->ah_len)))
     495             : 
     496             : #define OFP_BUCKETS_FOREACH(head, end, curr)                                    \
     497             : for ((curr) = (head); (caddr_t)curr < ((caddr_t)head + (end));                       \
     498             :      (curr) = (struct ofp_bucket *)((caddr_t)(curr) + ntohs((curr)->b_len)))
     499             : 
     500             : 
     501             : /*
     502             :  * OpenFlow protocol message handlers
     503             :  */
     504             : struct ofp_msg_class {
     505             :         uint8_t         msg_type;
     506             :         ofp_msg_handler msg_handler;
     507             : };
     508             : struct ofp_msg_class ofp_msg_table[] = {
     509             :         { OFP_T_HELLO,                          swofp_recv_hello },
     510             :         { OFP_T_ERROR,                          NULL /* unsupported */ },
     511             :         { OFP_T_ECHO_REQUEST,                   swofp_recv_echo },
     512             :         { OFP_T_ECHO_REPLY,                     NULL /* from switch */ },
     513             :         { OFP_T_EXPERIMENTER,                   NULL /* unsupported */ },
     514             :         { OFP_T_FEATURES_REQUEST,               swofp_recv_features_req },
     515             :         { OFP_T_FEATURES_REPLY,                 NULL /* from switch */ },
     516             :         { OFP_T_GET_CONFIG_REQUEST,             swofp_recv_config_req },
     517             :         { OFP_T_GET_CONFIG_REPLY,               NULL /* from switch */ },
     518             :         { OFP_T_SET_CONFIG,                     swofp_recv_set_config },
     519             :         { OFP_T_PACKET_IN,                      NULL /* from switch */ },
     520             :         { OFP_T_FLOW_REMOVED,                   NULL /* from switch */ },
     521             :         { OFP_T_PORT_STATUS,                    NULL /* from switch */ },
     522             :         { OFP_T_PACKET_OUT,                     swofp_recv_packet_out },
     523             :         { OFP_T_FLOW_MOD,                       swofp_flow_mod },
     524             :         { OFP_T_GROUP_MOD,                      swofp_group_mod },
     525             :         { OFP_T_PORT_MOD,                       NULL /* unsupported */ },
     526             :         { OFP_T_TABLE_MOD,                      NULL /* unsupported */ },
     527             :         { OFP_T_MULTIPART_REQUEST,              swofp_multipart_req },
     528             :         { OFP_T_MULTIPART_REPLY,                NULL /* from switch */ },
     529             :         { OFP_T_BARRIER_REQUEST,                swofp_barrier_req },
     530             :         { OFP_T_BARRIER_REPLY,                  NULL /* from switch */ },
     531             :         { OFP_T_QUEUE_GET_CONFIG_REQUEST,       NULL /* unsupported */ },
     532             :         { OFP_T_QUEUE_GET_CONFIG_REPLY,         NULL /* from switch */ },
     533             :         { OFP_T_ROLE_REQUEST,                   NULL /* unsupported */ },
     534             :         { OFP_T_ROLE_REPLY,                     NULL /* from switch */ },
     535             :         { OFP_T_GET_ASYNC_REQUEST,              NULL /* unsupported */ },
     536             :         { OFP_T_GET_ASYNC_REPLY,                NULL /* from switch */ },
     537             :         { OFP_T_SET_ASYNC,                      NULL /* unsupported */ },
     538             :         { OFP_T_METER_MOD,                      NULL /* unsupported */ }
     539             : };
     540             : 
     541             : 
     542             : /*
     543             : * OpenFlow protocol modification flow message command handlers
     544             : */
     545             : struct ofp_flow_mod_class {
     546             :         uint8_t          ofm_cmd_type;
     547             :         ofp_msg_handler  ofm_cmd_handler;
     548             : };
     549             : struct ofp_flow_mod_class ofp_flow_mod_table[] = {
     550             :         { OFP_FLOWCMD_ADD,              swofp_flow_mod_cmd_add },
     551             :         { OFP_FLOWCMD_MODIFY,           swofp_flow_mod_cmd_modify },
     552             :         { OFP_FLOWCMD_MODIFY_STRICT,    swofp_flow_mod_cmd_modify_strict },
     553             :         { OFP_FLOWCMD_DELETE,           swofp_flow_mod_cmd_delete },
     554             :         { OFP_FLOWCMD_DELETE_STRICT,    swofp_flow_mod_cmd_delete_strict },
     555             : };
     556             : 
     557             : /*
     558             :  * OpenFlow protocol multipart handlers
     559             :  */
     560             : struct ofp_mpmsg_class {
     561             :         uint8_t          msgsg_type;
     562             :         ofp_msg_handler  mpmsg_handler;
     563             : };
     564             : struct ofp_mpmsg_class ofp_mpmsg_table[] = {
     565             :         { OFP_MP_T_DESC,                swofp_mp_recv_desc },
     566             :         { OFP_MP_T_FLOW,                swofp_mp_recv_flow },
     567             :         { OFP_MP_T_AGGREGATE,           swofp_mp_recv_aggregate_flow_stat },
     568             :         { OFP_MP_T_TABLE,               swofp_mp_recv_table_stats },
     569             :         { OFP_MP_T_PORT_STATS,          swofp_mp_recv_port_stats },
     570             :         { OFP_MP_T_QUEUE,               NULL },
     571             :         { OFP_MP_T_GROUP,               NULL },
     572             :         { OFP_MP_T_GROUP_DESC,          swofp_mp_recv_group_desc },
     573             :         { OFP_MP_T_GROUP_FEATURES,      NULL },
     574             :         { OFP_MP_T_METER,               NULL },
     575             :         { OFP_MP_T_METER_CONFIG,        NULL },
     576             :         { OFP_MP_T_METER_FEATURES,      NULL },
     577             :         { OFP_MP_T_TABLE_FEATURES,      swofp_mp_recv_table_features },
     578             :         { OFP_MP_T_PORT_DESC,           swofp_mp_recv_port_desc }
     579             : };
     580             : 
     581             : /*
     582             :  * OpenFlow OXM match handlers
     583             :  */
     584             : #define SWOFP_MATCH_MASK        0x1
     585             : #define SWOFP_MATCH_WILDCARD    0x2
     586             : 
     587             : struct ofp_oxm_class {
     588             :         uint8_t  oxm_field;
     589             :         uint8_t  oxm_len; /* This length defined by speficication */
     590             :         uint8_t  oxm_flags;
     591             :         int     (*oxm_match)(struct switch_flow_classify *,
     592             :                     struct ofp_ox_match *);
     593             :         int     (*oxm_set)(struct switch_flow_classify *,
     594             :                     struct ofp_ox_match *);
     595             :         int     (*oxm_cmp)(struct ofp_ox_match *,
     596             :                     struct ofp_ox_match *, int);
     597             : };
     598             : 
     599             : /*
     600             :  * Handlers for basic class for OpenFlow
     601             :  */
     602             : struct ofp_oxm_class ofp_oxm_handlers[] = {
     603             :         {
     604             :                 OFP_XM_T_IN_PORT,
     605             :                 sizeof(uint32_t),
     606             :                 0,
     607             :                 swofp_ox_match_uint32,          NULL,
     608             :                 swofp_ox_cmp_data
     609             :         },
     610             :         {
     611             :                 OFP_XM_T_IN_PHY_PORT,
     612             :                 sizeof(uint32_t),
     613             :                 0,
     614             :                 NULL,                           NULL,
     615             :                 NULL
     616             :         },
     617             :         {
     618             :                 OFP_XM_T_META,
     619             :                 sizeof(uint64_t),
     620             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     621             :                 swofp_ox_match_uint64,  NULL,
     622             :                 NULL
     623             :         },
     624             :         {
     625             :                 OFP_XM_T_ETH_DST,
     626             :                 ETHER_ADDR_LEN,
     627             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     628             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     629             :                 swofp_ox_cmp_ether_addr
     630             :         },
     631             :         {
     632             :                 OFP_XM_T_ETH_SRC,
     633             :                 ETHER_ADDR_LEN,
     634             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     635             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     636             :                 swofp_ox_cmp_ether_addr
     637             :         },
     638             :         {
     639             :                 OFP_XM_T_ETH_TYPE,
     640             :                 sizeof(uint16_t),
     641             :                 SWOFP_MATCH_WILDCARD,
     642             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     643             :                 swofp_ox_cmp_data
     644             :         },
     645             :         {
     646             :                 OFP_XM_T_VLAN_VID,
     647             :                 sizeof(uint16_t),
     648             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     649             :                 swofp_ox_match_vlan_vid,        swofp_ox_set_vlan_vid,
     650             :                 swofp_ox_cmp_vlan_vid
     651             :         },
     652             :         {
     653             :                 OFP_XM_T_VLAN_PCP,
     654             :                 sizeof(uint8_t),
     655             :                 SWOFP_MATCH_WILDCARD,
     656             :                 swofp_ox_match_uint8,           swofp_ox_set_uint16,
     657             :                 swofp_ox_cmp_data
     658             :         },
     659             :         {
     660             :                 OFP_XM_T_IP_DSCP,
     661             :                 sizeof(uint8_t),
     662             :                 SWOFP_MATCH_WILDCARD,
     663             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     664             :                 swofp_ox_cmp_data
     665             :         },
     666             :         {
     667             :                 OFP_XM_T_IP_ECN,
     668             :                 sizeof(uint8_t),
     669             :                 SWOFP_MATCH_WILDCARD,
     670             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     671             :                 swofp_ox_cmp_data
     672             :         },
     673             :         {
     674             :                 OFP_XM_T_IP_PROTO,
     675             :                 sizeof(uint8_t),
     676             :                 SWOFP_MATCH_WILDCARD,
     677             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     678             :                 swofp_ox_cmp_data
     679             :         },
     680             :         {
     681             :                 OFP_XM_T_IPV4_SRC,
     682             :                 sizeof(uint32_t),
     683             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     684             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     685             :                 swofp_ox_cmp_ipv4_addr
     686             :         },
     687             :         {
     688             :                 OFP_XM_T_IPV4_DST,
     689             :                 sizeof(uint32_t),
     690             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     691             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     692             :                 swofp_ox_cmp_ipv4_addr
     693             :         },
     694             :         {
     695             :                 OFP_XM_T_TCP_SRC,
     696             :                 sizeof(uint16_t),
     697             :                 SWOFP_MATCH_WILDCARD,
     698             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     699             :                 swofp_ox_cmp_data
     700             :         },
     701             :         {
     702             :                 OFP_XM_T_TCP_DST,
     703             :                 sizeof(uint16_t),
     704             :                 SWOFP_MATCH_WILDCARD,
     705             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     706             :                 swofp_ox_cmp_data
     707             :         },
     708             :         {
     709             :                 OFP_XM_T_UDP_SRC,
     710             :                 sizeof(uint16_t),
     711             :                 SWOFP_MATCH_WILDCARD,
     712             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     713             :                 swofp_ox_cmp_data
     714             :         },
     715             :         {
     716             :                 OFP_XM_T_UDP_DST,
     717             :                 sizeof(uint16_t),
     718             :                 SWOFP_MATCH_WILDCARD,
     719             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     720             :                 swofp_ox_cmp_data
     721             :         },
     722             :         {
     723             :                 OFP_XM_T_SCTP_SRC,
     724             :                 sizeof(uint16_t),
     725             :                 SWOFP_MATCH_WILDCARD,
     726             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     727             :                 swofp_ox_cmp_data
     728             :         },
     729             :         {
     730             :                 OFP_XM_T_SCTP_DST,
     731             :                 sizeof(uint16_t),
     732             :                 SWOFP_MATCH_WILDCARD,
     733             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     734             :                 swofp_ox_cmp_data
     735             :         },
     736             :         {
     737             :                 OFP_XM_T_ICMPV4_TYPE,
     738             :                 sizeof(uint8_t),
     739             :                 SWOFP_MATCH_WILDCARD,
     740             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     741             :                 swofp_ox_cmp_data
     742             :         },
     743             :         {
     744             :                 OFP_XM_T_ICMPV4_CODE,
     745             :                 sizeof(uint8_t),
     746             :                 SWOFP_MATCH_WILDCARD,
     747             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     748             :                 swofp_ox_cmp_data
     749             :         },
     750             :         {
     751             :                 OFP_XM_T_ARP_OP,
     752             :                 sizeof(uint16_t),
     753             :                 SWOFP_MATCH_WILDCARD,
     754             :                 swofp_ox_match_uint16,          swofp_ox_set_uint16,
     755             :                 swofp_ox_cmp_data
     756             :         },
     757             :         {
     758             :                 OFP_XM_T_ARP_SPA,
     759             :                 sizeof(uint32_t),
     760             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     761             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     762             :                 swofp_ox_cmp_ipv4_addr
     763             :         },
     764             :         {
     765             :                 OFP_XM_T_ARP_TPA,
     766             :                 sizeof(uint32_t),
     767             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     768             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     769             :                 swofp_ox_cmp_ipv4_addr
     770             :         },
     771             :         {
     772             :                 OFP_XM_T_ARP_SHA,
     773             :                 ETHER_ADDR_LEN,
     774             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     775             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     776             :                 swofp_ox_cmp_ether_addr
     777             :         },
     778             :         {
     779             :                 OFP_XM_T_ARP_THA,
     780             :                 ETHER_ADDR_LEN,
     781             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     782             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     783             :                 swofp_ox_cmp_ether_addr
     784             :         },
     785             : #ifdef INET6
     786             :         {
     787             :                 OFP_XM_T_IPV6_SRC,
     788             :                 sizeof(struct in6_addr),
     789             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     790             :                 swofp_ox_match_ipv6_addr,       swofp_ox_set_ipv6_addr,
     791             :                 swofp_ox_cmp_ipv6_addr
     792             :         },
     793             :         {
     794             :                 OFP_XM_T_IPV6_DST,
     795             :                 sizeof(struct in6_addr),
     796             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     797             :                 swofp_ox_match_ipv6_addr,       swofp_ox_set_ipv6_addr,
     798             :                 swofp_ox_cmp_ipv6_addr
     799             :         },
     800             :         {
     801             :                 OFP_XM_T_IPV6_FLABEL,
     802             :                 sizeof(uint32_t),
     803             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     804             :                 swofp_ox_match_uint32,          swofp_ox_set_uint32,
     805             :                 swofp_ox_cmp_data
     806             :         },
     807             :         {
     808             :                 OFP_XM_T_ICMPV6_TYPE,
     809             :                 sizeof(uint8_t),
     810             :                 SWOFP_MATCH_WILDCARD,
     811             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     812             :                 swofp_ox_cmp_data
     813             :         },
     814             :         {
     815             :                 OFP_XM_T_ICMPV6_CODE,
     816             :                 sizeof(uint8_t),
     817             :                 SWOFP_MATCH_WILDCARD,
     818             :                 swofp_ox_match_uint8,           swofp_ox_set_uint8,
     819             :                 swofp_ox_cmp_data
     820             :         },
     821             :         {
     822             :                 OFP_XM_T_IPV6_ND_TARGET,
     823             :                 sizeof(struct in6_addr),
     824             :                 SWOFP_MATCH_WILDCARD,
     825             :                 swofp_ox_match_ipv6_addr,       swofp_ox_set_ipv6_addr,
     826             :                 swofp_ox_cmp_ipv6_addr
     827             :         },
     828             :         {
     829             :                 OFP_XM_T_IPV6_ND_SLL,
     830             :                 ETHER_ADDR_LEN,
     831             :                 SWOFP_MATCH_WILDCARD,
     832             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     833             :                 swofp_ox_cmp_ether_addr
     834             :         },
     835             :         {
     836             :                 OFP_XM_T_IPV6_ND_TLL,
     837             :                 ETHER_ADDR_LEN,
     838             :                 SWOFP_MATCH_WILDCARD,
     839             :                 swofp_ox_match_ether_addr,      swofp_ox_set_ether_addr,
     840             :                 swofp_ox_cmp_ether_addr
     841             :         },
     842             : #endif /* INET6 */
     843             :         {
     844             :                 OFP_XM_T_MPLS_LABEL,
     845             :                 sizeof(uint32_t),
     846             :                 SWOFP_MATCH_WILDCARD,
     847             :                 NULL,                           NULL,
     848             :                 NULL
     849             :         },
     850             :         {
     851             :                 OFP_XM_T_MPLS_TC,
     852             :                 sizeof(uint8_t),
     853             :                 SWOFP_MATCH_WILDCARD,
     854             :                 NULL,                           NULL,
     855             :                 NULL
     856             :         },
     857             :         {
     858             :                 OFP_XM_T_MPLS_BOS,
     859             :                 sizeof(uint8_t),
     860             :                 SWOFP_MATCH_WILDCARD,
     861             :                 NULL,                           NULL,
     862             :                 NULL
     863             :         },
     864             :         {
     865             :                 OFP_XM_T_PBB_ISID,
     866             :                 3,
     867             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     868             :                 NULL,                           NULL,
     869             :                 NULL
     870             :         },
     871             :         {
     872             :                 OFP_XM_T_TUNNEL_ID,
     873             :                 sizeof(uint64_t),
     874             :                 SWOFP_MATCH_WILDCARD,
     875             :                 swofp_ox_match_uint64,          swofp_ox_set_uint64,
     876             :                 swofp_ox_cmp_data
     877             :         },
     878             :         {
     879             :                 OFP_XM_T_IPV6_EXTHDR,
     880             :                 sizeof(uint16_t),
     881             :                 SWOFP_MATCH_WILDCARD,
     882             :                 NULL,                           NULL,
     883             :                 NULL
     884             :         },
     885             : };
     886             : 
     887             : /*
     888             :  * Handlers for backward compatibility with NXM
     889             :  */
     890             : struct ofp_oxm_class ofp_oxm_nxm_handlers[] = {
     891             :         {
     892             :                 OFP_XM_NXMT_TUNNEL_ID,
     893             :                 sizeof(uint64_t),
     894             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     895             :                 swofp_ox_match_uint64,          swofp_ox_set_uint64,
     896             :                 swofp_ox_cmp_data
     897             :         },
     898             :         {
     899             :                 OFP_XM_NXMT_TUNNEL_IPV4_SRC,
     900             :                 sizeof(uint32_t),
     901             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     902             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     903             :                 swofp_ox_cmp_ipv4_addr
     904             :         },
     905             :         {
     906             :                 OFP_XM_NXMT_TUNNEL_IPV4_DST,
     907             :                 sizeof(uint32_t),
     908             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     909             :                 swofp_ox_match_ipv4_addr,       swofp_ox_set_ipv4_addr,
     910             :                 swofp_ox_cmp_ipv4_addr
     911             :         },
     912             : #ifdef INET6
     913             :         {
     914             :                 OFP_XM_NXMT_TUNNEL_IPV6_SRC,
     915             :                 sizeof(struct in6_addr),
     916             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     917             :                 swofp_ox_match_ipv6_addr,       swofp_ox_set_ipv6_addr,
     918             :                 swofp_ox_cmp_ipv6_addr
     919             :         },
     920             :         {
     921             :                 OFP_XM_NXMT_TUNNEL_IPV6_DST,
     922             :                 sizeof(struct in6_addr),
     923             :                 SWOFP_MATCH_MASK|SWOFP_MATCH_WILDCARD,
     924             :                 swofp_ox_match_ipv6_addr,       swofp_ox_set_ipv6_addr,
     925             :                 swofp_ox_cmp_ipv6_addr
     926             :         },
     927             : #endif /* INET6 */
     928             : };
     929             : 
     930             : /*
     931             :  * OpenFlow action handlers
     932             :  */
     933             : struct ofp_action_handler {
     934             :         uint16_t         action_type;
     935             :         struct mbuf *   (*action)(struct switch_softc *,  struct mbuf *,
     936             :             struct swofp_pipeline_desc *, struct ofp_action_header *);
     937             : };
     938             : struct ofp_action_handler ofp_action_handlers[] = {
     939             :         /*
     940             :          * Following order complies with action set order in
     941             :          * OpenFlow Switch Specification (ver. 1.3.5)
     942             :          */
     943             :         {
     944             :                 OFP_ACTION_COPY_TTL_IN,
     945             :                 NULL
     946             :         },
     947             :         {
     948             :                 OFP_ACTION_POP_MPLS,
     949             :                 NULL
     950             :         },
     951             :         {
     952             :                 OFP_ACTION_POP_PBB,
     953             :                 NULL
     954             :         },
     955             :         {
     956             :                 OFP_ACTION_POP_VLAN,
     957             :                 swofp_action_pop_vlan
     958             :         },
     959             :         {
     960             :                 OFP_ACTION_PUSH_MPLS,
     961             :                 NULL
     962             :         },
     963             :         {
     964             :                 OFP_ACTION_PUSH_PBB,
     965             :                 NULL
     966             :         },
     967             :         {
     968             :                 OFP_ACTION_PUSH_VLAN,
     969             :                 swofp_action_push_vlan
     970             :         },
     971             :         {
     972             :                 OFP_ACTION_COPY_TTL_OUT,
     973             :                 NULL
     974             :         },
     975             :         {
     976             :                 OFP_ACTION_DEC_NW_TTL,
     977             :                 NULL
     978             :         },
     979             :         {
     980             :                 OFP_ACTION_DEC_MPLS_TTL,
     981             :                 NULL
     982             :         },
     983             :         {
     984             :                 OFP_ACTION_SET_MPLS_TTL,
     985             :                 NULL
     986             :         },
     987             :         {
     988             :                 OFP_ACTION_SET_NW_TTL,
     989             :                 NULL
     990             :         },
     991             :         {
     992             :                 OFP_ACTION_SET_FIELD,
     993             :                 swofp_action_set_field
     994             :         },
     995             :         {
     996             :                 OFP_ACTION_SET_QUEUE,
     997             :                 NULL
     998             :         },
     999             :         {
    1000             :                 OFP_ACTION_GROUP,
    1001             :                 swofp_action_group
    1002             :         },
    1003             :         {
    1004             :                 OFP_ACTION_OUTPUT,
    1005             :                 swofp_action_output
    1006             :         },
    1007             :         {
    1008             :                 OFP_ACTION_EXPERIMENTER,
    1009             :                 NULL
    1010             :         }, /* XXX Where is best position? */
    1011             : };
    1012             : 
    1013             : extern struct pool swfcl_pool;
    1014             : struct pool swpld_pool;
    1015             : 
    1016             : void
    1017           0 : swofp_attach(void)
    1018             : {
    1019           0 :         pool_init(&swpld_pool, sizeof(struct swofp_pipeline_desc), 0, 0, 0,
    1020             :             "swpld", NULL);
    1021           0 : }
    1022             : 
    1023             : 
    1024             : int
    1025           0 : swofp_create(struct switch_softc *sc)
    1026             : {
    1027             :         struct swofp_ofs        *swofs;
    1028             :         int                      error;
    1029             : 
    1030           0 :         swofs = malloc(sizeof(*swofs), M_DEVBUF, M_NOWAIT|M_ZERO);
    1031           0 :         if (swofs == NULL)
    1032           0 :                 return (ENOMEM);
    1033             : 
    1034           0 :         sc->sc_ofs = swofs;
    1035             : 
    1036           0 :         TAILQ_INIT(&swofs->swofs_table_list);
    1037             : 
    1038             :         /*
    1039             :          * A table with id 0 must exist
    1040             :          */
    1041           0 :         if ((swofp_flow_table_add(sc, 0)) == NULL) {
    1042             :                 error = ENOBUFS;
    1043           0 :                 free(swofs, M_DEVBUF, sizeof(*swofs));
    1044           0 :                 return (error);
    1045             :         }
    1046             : 
    1047           0 :         swofs->swofs_xidnxt = 1;
    1048           0 :         arc4random_buf(&swofs->swofs_datapath_id,
    1049             :             sizeof(swofs->swofs_datapath_id));
    1050             : 
    1051           0 :         timeout_set(&swofs->swofs_flow_timeout, swofp_timer, sc);
    1052           0 :         timeout_add_sec(&swofs->swofs_flow_timeout, 10);
    1053             : 
    1054             :         /* TODO: Configured from ifconfig  */
    1055           0 :         swofs->swofs_group_max_table = 1000;
    1056           0 :         swofs->swofs_flow_max_entry = 10000;
    1057             : 
    1058           0 :         sc->sc_capabilities |= SWITCH_CAP_OFP;
    1059           0 :         sc->switch_process_forward = swofp_forward_ofs;
    1060             : 
    1061             : #if NBPFILTER > 0
    1062           0 :         bpfattach(&sc->sc_ofbpf, &sc->sc_if, DLT_OPENFLOW,
    1063             :             sizeof(struct ofp_header));
    1064             : #endif
    1065             : 
    1066           0 :         return (0);
    1067           0 : }
    1068             : 
    1069             : void
    1070           0 : swofp_destroy(struct switch_softc *sc)
    1071             : {
    1072           0 :         struct swofp_ofs        *swofs = sc->sc_ofs;
    1073             : 
    1074           0 :         if ((sc->sc_capabilities & SWITCH_CAP_OFP) == 0 || swofs == NULL)
    1075           0 :                 return;
    1076             : 
    1077           0 :         timeout_del(&swofs->swofs_flow_timeout);
    1078             : 
    1079           0 :         sc->sc_capabilities &= ~SWITCH_CAP_OFP;
    1080           0 :         sc->switch_process_forward = NULL;
    1081             : 
    1082           0 :         swofp_group_entry_delete_all(sc);
    1083             : 
    1084           0 :         free(swofs, M_DEVBUF, sizeof(*swofs));
    1085           0 : }
    1086             : 
    1087             : int
    1088           0 : swofp_init(struct switch_softc *sc)
    1089             : {
    1090           0 :         sc->sc_swdev->swdev_input = swofp_input;
    1091           0 :         swofp_send_hello(sc);
    1092           0 :         return (0);
    1093             : }
    1094             : 
    1095             : uint32_t
    1096           0 : swofp_assign_portno(struct switch_softc *sc, uint32_t req)
    1097             : {
    1098             :         struct switch_port      *swpo;
    1099             :         uint32_t                 candidate;
    1100             : 
    1101           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    1102           0 :                 if (swpo->swpo_port_no == req)
    1103             :                         break;
    1104             :         }
    1105           0 :         if (swpo == NULL)
    1106           0 :                 return (req);
    1107             : 
    1108             :         /* XXX
    1109             :          * OS's ifindex is "short", so it expect that floowing is unique
    1110             :          */
    1111           0 :         candidate = (req << 16) | req;
    1112           0 :         while (1) {
    1113           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    1114           0 :                         if (swpo->swpo_port_no == candidate)
    1115             :                                 break;
    1116             :                 }
    1117           0 :                 if (swpo == NULL)
    1118           0 :                         return (candidate);
    1119             : 
    1120           0 :                 if (candidate < OFP_PORT_MAX)
    1121           0 :                         candidate++;
    1122             :                 else
    1123             :                         candidate = 0;
    1124             :         }
    1125           0 : }
    1126             : 
    1127             : int
    1128           0 : swofp_ioctl(struct ifnet *ifp, unsigned long cmd, caddr_t data)
    1129             : {
    1130           0 :         struct switch_softc     *sc = ifp->if_softc;
    1131           0 :         struct swofp_ofs        *swofs = sc->sc_ofs;
    1132           0 :         struct ifbrparam        *bparam = (struct ifbrparam *)data;
    1133           0 :         struct ifbreq           *breq = (struct ifbreq *)data;
    1134             :         struct switch_port      *swpo;
    1135             :         struct ifnet            *ifs;
    1136             :         int                      error = 0;
    1137             : 
    1138           0 :         switch (cmd) {
    1139             :         case SIOCSWGDPID:
    1140           0 :                 memcpy(&bparam->ifbrp_datapath, &swofs->swofs_datapath_id,
    1141             :                     sizeof(uint64_t));
    1142           0 :                 break;
    1143             :         case SIOCSWSDPID:
    1144           0 :                 if ((error = suser(curproc)) != 0)
    1145             :                         break;
    1146           0 :                 memcpy(&swofs->swofs_datapath_id, &bparam->ifbrp_datapath,
    1147             :                     sizeof(uint64_t));
    1148           0 :                 break;
    1149             :         case SIOCSWGMAXFLOW:
    1150           0 :                 bparam->ifbrp_maxflow = swofs->swofs_flow_max_entry;
    1151           0 :                 break;
    1152             :         case SIOCSWGMAXGROUP:
    1153           0 :                 bparam->ifbrp_maxgroup = swofs->swofs_group_max_table;
    1154           0 :                 break;
    1155             :         case SIOCSWSPORTNO:
    1156           0 :                 if ((error = suser(curproc)) != 0)
    1157             :                         break;
    1158             : 
    1159           0 :                 if (breq->ifbr_portno >= OFP_PORT_MAX)
    1160           0 :                         return (EINVAL);
    1161             : 
    1162           0 :                 if ((ifs = ifunit(breq->ifbr_ifsname)) == NULL)
    1163           0 :                         return (ENOENT);
    1164             : 
    1165           0 :                 if (ifs->if_switchport == NULL)
    1166           0 :                         return (ENOENT);
    1167             : 
    1168           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    1169           0 :                         if (swpo->swpo_port_no == breq->ifbr_portno)
    1170           0 :                                 return (EEXIST);
    1171             :                 }
    1172             : 
    1173           0 :                 swpo = (struct switch_port *)ifs->if_switchport;
    1174           0 :                 swpo->swpo_port_no = breq->ifbr_portno;
    1175             : 
    1176           0 :                 break;
    1177             :         default:
    1178             :                 error = ENOTTY;
    1179           0 :                 break;
    1180             :         }
    1181             : 
    1182           0 :         return (error);
    1183           0 : }
    1184             : 
    1185             : /* TODO: Optimization */
    1186             : struct ofp_oxm_class *
    1187           0 : swofp_lookup_oxm_handler(struct ofp_ox_match *oxm)
    1188             : {
    1189             :         struct ofp_oxm_class    *handlers;
    1190             :         uint8_t                  oxm_field;
    1191             :         int                      i, len;
    1192             : 
    1193           0 :         switch (ntohs(oxm->oxm_class)) {
    1194             :         case OFP_OXM_C_OPENFLOW_BASIC:
    1195             :                 handlers = ofp_oxm_handlers;
    1196             :                 len = nitems(ofp_oxm_handlers);
    1197           0 :                 break;
    1198             :         case OFP_OXM_C_NXM_1:
    1199             :                 handlers = ofp_oxm_nxm_handlers;
    1200             :                 len = nitems(ofp_oxm_nxm_handlers);
    1201           0 :                 break;
    1202             :         default:
    1203           0 :                 return (NULL);
    1204             :         }
    1205             : 
    1206           0 :         oxm_field = OFP_OXM_GET_FIELD(oxm);
    1207             : 
    1208           0 :         for (i = 0; i < len ; i++) {
    1209           0 :                 if (handlers[i].oxm_field == oxm_field)
    1210           0 :                         return (&handlers[i]);
    1211             :         }
    1212             : 
    1213           0 :         return (NULL);
    1214           0 : }
    1215             : 
    1216             : ofp_msg_handler
    1217           0 : swofp_lookup_msg_handler(uint8_t type)
    1218             : {
    1219           0 :         if (type >= OFP_T_TYPE_MAX)
    1220           0 :                 return (NULL);
    1221             :         else
    1222           0 :                 return (ofp_msg_table[type].msg_handler);
    1223           0 : }
    1224             : 
    1225             : ofp_msg_handler
    1226           0 : swofp_lookup_mpmsg_handler(uint16_t type)
    1227             : {
    1228           0 :         if (type >= nitems(ofp_mpmsg_table))
    1229           0 :                 return (NULL);
    1230             :         else
    1231           0 :                 return (ofp_mpmsg_table[type].mpmsg_handler);
    1232           0 : }
    1233             : 
    1234             : struct ofp_action_handler *
    1235           0 : swofp_lookup_action_handler(uint16_t type)
    1236             : {
    1237             :         int     i;
    1238             : 
    1239           0 :         for (i = 0; i < nitems(ofp_action_handlers); i++) {
    1240           0 :                 if (ofp_action_handlers[i].action_type == type)
    1241           0 :                         return &(ofp_action_handlers[i]);
    1242             :         }
    1243             : 
    1244           0 :         return (NULL);
    1245           0 : }
    1246             : 
    1247             : struct swofp_pipeline_desc *
    1248           0 : swofp_pipeline_desc_create(struct switch_flow_classify *swfcl)
    1249             : {
    1250             :         struct swofp_pipeline_desc      *swpld = NULL;
    1251             :         struct swofp_action_set         *swas = NULL;
    1252             :         int                              i;
    1253             : 
    1254           0 :         swpld = pool_get(&swpld_pool, PR_NOWAIT|PR_ZERO);
    1255           0 :         if (swpld == NULL)
    1256           0 :                 return (NULL);
    1257             : 
    1258             :         /*
    1259             :          * ofp_action_handlers is sorted by applying action-set order,
    1260             :          * so it can be used for initializer for action-set.
    1261             :          */
    1262           0 :         swas = swpld->swpld_action_set;
    1263           0 :         for (i = 0; i < nitems(ofp_action_handlers); i++) {
    1264           0 :                 swas[i].swas_type = ofp_action_handlers[i].action_type;
    1265           0 :                 if (swas[i].swas_type == OFP_ACTION_SET_FIELD)
    1266           0 :                         swas[i].swas_action = (struct ofp_action_header *)
    1267           0 :                             swpld->swpld_set_fields;
    1268             :                 else
    1269           0 :                         swas[i].swas_action = NULL;
    1270             :         }
    1271             : 
    1272           0 :         swpld->swpld_swfcl = swfcl;
    1273             : 
    1274           0 :         return (swpld);
    1275           0 : }
    1276             : 
    1277             : void
    1278           0 : swofp_pipeline_desc_destroy(struct swofp_pipeline_desc *swpld)
    1279             : {
    1280           0 :         switch_swfcl_free(&swpld->swpld_pre_swfcl);
    1281           0 :         pool_put(&swpld_pool, swpld);
    1282           0 : }
    1283             : 
    1284             : struct swofp_flow_table *
    1285           0 : swofp_flow_table_lookup(struct switch_softc *sc, uint16_t table_id)
    1286             : {
    1287           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1288             :         struct swofp_flow_table *swft;
    1289             : 
    1290           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    1291           0 :                 if (swft->swft_table_id == table_id)
    1292           0 :                         return (swft);
    1293             :         }
    1294             : 
    1295           0 :         return (NULL);
    1296           0 : }
    1297             : 
    1298             : struct swofp_flow_table *
    1299           0 : swofp_flow_table_add(struct switch_softc *sc, uint16_t table_id)
    1300             : {
    1301           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1302             :         struct swofp_flow_table *swft, *new;
    1303             : 
    1304           0 :         if ((swft = swofp_flow_table_lookup(sc, table_id)) != NULL)
    1305           0 :                 return (swft);
    1306             : 
    1307           0 :         if ((new = malloc(sizeof(*new), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
    1308           0 :                 return (NULL);
    1309             : 
    1310           0 :         new->swft_table_id = table_id;
    1311           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    1312           0 :                 if (table_id < swft->swft_table_id)
    1313             :                         break;
    1314             :         }
    1315             : 
    1316           0 :         if (swft)
    1317           0 :                 TAILQ_INSERT_BEFORE(swft, new, swft_table_next);
    1318             :         else
    1319           0 :                 TAILQ_INSERT_TAIL(&ofs->swofs_table_list, new, swft_table_next);
    1320             : 
    1321             :         DPRINTF(sc, "add openflow flow table (id:%d)\n", table_id);
    1322             : 
    1323           0 :         return (new);
    1324           0 : }
    1325             : 
    1326             : int
    1327           0 : swofp_flow_table_delete(struct switch_softc *sc, uint16_t table_id)
    1328             : {
    1329           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1330             :         struct swofp_flow_table *swft;
    1331             :         struct swofp_flow_entry *swfe, *tswfe;
    1332             : 
    1333           0 :         if ((swft = swofp_flow_table_lookup(sc, table_id)) == NULL)
    1334           0 :                 return ENOENT;
    1335             : 
    1336           0 :         LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
    1337             :                 /*
    1338             :                  * Flows are deleted force becouse of deleting table,
    1339             :                  * s it's not necessary to send flow remove message.
    1340             :                  */
    1341           0 :                 swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED);
    1342           0 :                 swofp_flow_entry_delete(sc, swft, swfe,
    1343             :                     OFP_FLOWREM_REASON_DELETE);
    1344             :         }
    1345             : 
    1346           0 :         TAILQ_REMOVE(&ofs->swofs_table_list, swft, swft_table_next);
    1347           0 :         free(swft, M_DEVBUF, sizeof(*swft));
    1348             : 
    1349             :         DPRINTF(sc, "delete flow table (id:%d)\n", table_id);
    1350             : 
    1351           0 :         return 0;
    1352           0 : }
    1353             : 
    1354             : void
    1355           0 : swofp_flow_table_delete_all(struct switch_softc *sc)
    1356             : {
    1357           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1358             :         struct swofp_flow_table *swft, *tswft;
    1359             :         int                      error;
    1360             : 
    1361           0 :         TAILQ_FOREACH_SAFE(swft, &ofs->swofs_table_list,
    1362             :             swft_table_next, tswft) {
    1363           0 :                 if ((error = swofp_flow_table_delete(sc,swft->swft_table_id)))
    1364           0 :                         log(LOG_ERR, "can't delete table id:%d (error:%d)\n",
    1365           0 :                             swft->swft_table_id, error);
    1366             :         }
    1367           0 : }
    1368             : 
    1369             : struct swofp_group_entry *
    1370           0 : swofp_group_entry_lookup(struct switch_softc *sc, uint32_t group_id)
    1371             : {
    1372           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    1373             :         struct swofp_group_entry        *swge;
    1374             : 
    1375           0 :         LIST_FOREACH(swge, &ofs->swofs_group_table, swge_next) {
    1376           0 :                 if (swge->swge_group_id == group_id)
    1377           0 :                         return swge;
    1378             :         }
    1379             : 
    1380           0 :         return (NULL);
    1381           0 : }
    1382             : 
    1383             : int
    1384           0 : swofp_group_entry_add(struct switch_softc *sc, struct swofp_group_entry *swge)
    1385             : {
    1386           0 :         struct swofp_ofs *ofs = sc->sc_ofs;
    1387             : 
    1388           0 :         LIST_INSERT_HEAD(&ofs->swofs_group_table, swge, swge_next);
    1389           0 :         ofs->swofs_group_table_num++;
    1390             : 
    1391             :         DPRINTF(sc, "add group %d in group table (total %d)\n",
    1392             :             swge->swge_group_id, ofs->swofs_group_table_num);
    1393             : 
    1394           0 :         return (0);
    1395             : }
    1396             : 
    1397             : int
    1398           0 : swofp_group_entry_delete(struct switch_softc *sc,
    1399             :     struct swofp_group_entry *swge)
    1400             : {
    1401           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1402             :         struct swofp_flow_table *swft;
    1403             : 
    1404             :         DPRINTF(sc, "delete group %d in group table (total %d)\n",
    1405             :             swge->swge_group_id, ofs->swofs_group_table_num);
    1406             : 
    1407           0 :         LIST_REMOVE(swge, swge_next);
    1408           0 :         ofs->swofs_group_table_num--;
    1409             : 
    1410           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    1411           0 :                 swofp_flow_delete_on_table_by_group(sc, swft,
    1412           0 :                     swge->swge_group_id);
    1413             :         }
    1414             : 
    1415           0 :         free(swge->swge_buckets, M_DEVBUF, swge->swge_buckets_len);
    1416           0 :         free(swge, M_DEVBUF, sizeof(*swge));
    1417             : 
    1418           0 :         return (0);
    1419             : }
    1420             : 
    1421             : int
    1422           0 : swofp_group_entry_delete_all(struct switch_softc *sc)
    1423             : {
    1424           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    1425             :         struct swofp_group_entry        *swge, *tswge;
    1426             : 
    1427           0 :         LIST_FOREACH_SAFE(swge, &ofs->swofs_group_table, swge_next, tswge) {
    1428           0 :                 swofp_group_entry_delete(sc, swge);
    1429             :         }
    1430             : 
    1431           0 :         return (0);
    1432             : }
    1433             : 
    1434             : int
    1435           0 : swofp_validate_buckets(struct switch_softc *sc, struct mbuf *m, uint8_t type,
    1436             :     uint16_t *etype, uint16_t *error)
    1437             : {
    1438             :         struct ofp_group_mod    *ogm;
    1439             :         struct ofp_bucket       *bucket;
    1440             :         struct ofp_action_header *ah;
    1441             :         uint16_t                weight, remaining;
    1442             :         int                     start, len, off, num;
    1443             :         size_t                  blen;
    1444             : 
    1445           0 :         *etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
    1446             : 
    1447           0 :         ogm = mtod(m, struct ofp_group_mod *);
    1448             :         start = offsetof(struct ofp_group_mod, gm_buckets);
    1449           0 :         remaining = len = ntohs(ogm->gm_oh.oh_length) - start;
    1450             : 
    1451             :         /* Invalid packet size. */
    1452           0 :         if (len < 0) {
    1453           0 :                 *error = OFP_ERRGROUPMOD_INVALID_GROUP;
    1454           0 :                 return (-1);
    1455             :         }
    1456             : 
    1457             :         /* Indirect group type must always have one bucket. */
    1458           0 :         if (len < sizeof(*bucket) && type == OFP_GROUP_T_INDIRECT) {
    1459           0 :                 *error = OFP_ERRGROUPMOD_INVALID_GROUP;
    1460           0 :                 return (-1);
    1461             :         }
    1462             : 
    1463           0 :         for (off = start, num = 0; off < start + len; off += blen, num++) {
    1464           0 :                 bucket = (struct ofp_bucket *)(mtod(m, caddr_t) + off);
    1465             : 
    1466           0 :                 blen = ntohs(bucket->b_len);
    1467           0 :                 if (blen < sizeof(*bucket)) {
    1468           0 :                         *error = OFP_ERRGROUPMOD_BAD_BUCKET;
    1469           0 :                         return (-1);
    1470             :                 }
    1471             : 
    1472             :                 /* Validate that the bucket is smaller than the payload. */
    1473           0 :                 if (blen > remaining) {
    1474           0 :                         *etype = OFP_ERRTYPE_BAD_REQUEST;
    1475           0 :                         *error = OFP_ERRREQ_BAD_LEN;
    1476           0 :                         return (-1);
    1477             :                 }
    1478           0 :                 remaining -= blen;
    1479             : 
    1480             :                 /*
    1481             :                  * Validate weight
    1482             :                  */
    1483           0 :                 switch (type) {
    1484             :                 case OFP_GROUP_T_ALL:
    1485             :                 case OFP_GROUP_T_INDIRECT:
    1486             :                 case OFP_GROUP_T_FAST_FAILOVER:
    1487           0 :                         if (ntohs(bucket->b_weight) != 0) {
    1488           0 :                                 *error = OFP_ERRGROUPMOD_BAD_BUCKET;
    1489           0 :                                 return (-1);
    1490             :                         }
    1491             :                         break;
    1492             :                 case OFP_GROUP_T_SELECT:
    1493           0 :                         if (num > 1 && weight != ntohs(bucket->b_weight)) {
    1494           0 :                                 *error = OFP_ERRGROUPMOD_WEIGHT_UNSUPP;
    1495           0 :                                 return (-1);
    1496             :                         }
    1497             :                         break;
    1498             :                 }
    1499             : 
    1500             :                 /*
    1501             :                  * INDIRECT type has only one bucket
    1502             :                  */
    1503           0 :                 if (type == OFP_GROUP_T_INDIRECT && num > 1) {
    1504           0 :                         *error = OFP_ERRGROUPMOD_BAD_BUCKET;
    1505           0 :                         return (-1);
    1506             :                 }
    1507             : 
    1508           0 :                 weight = ntohs(bucket->b_weight);
    1509             : 
    1510             :                 /* Skip if there are no actions to validate. */
    1511           0 :                 if (blen == sizeof(*bucket))
    1512             :                         continue;
    1513             : 
    1514           0 :                 ah = (struct ofp_action_header *)
    1515           0 :                     (mtod(m, caddr_t) + off + sizeof(*bucket));
    1516           0 :                 if (swofp_validate_action(sc, ah, blen - sizeof(*bucket),
    1517             :                     error)) {
    1518           0 :                         *etype = OFP_ERRTYPE_BAD_ACTION;
    1519           0 :                         return (-1);
    1520             :                 }
    1521             :         }
    1522             : 
    1523           0 :         return (0);
    1524           0 : }
    1525             : 
    1526             : void
    1527           0 : swofp_flow_entry_table_free(struct ofp_instruction **table)
    1528             : {
    1529           0 :         if (*table) {
    1530           0 :                 free(*table, M_DEVBUF, ntohs((*table)->i_len));
    1531           0 :                 *table = NULL;
    1532           0 :         }
    1533           0 : }
    1534             : 
    1535             : void
    1536           0 : swofp_flow_entry_instruction_free(struct swofp_flow_entry *swfe)
    1537             : {
    1538           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1539           0 :             &swfe->swfe_goto_table);
    1540           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1541           0 :             &swfe->swfe_write_metadata);
    1542           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1543           0 :             &swfe->swfe_apply_actions);
    1544           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1545           0 :             &swfe->swfe_write_actions);
    1546           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1547           0 :             &swfe->swfe_clear_actions);
    1548           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1549           0 :             &swfe->swfe_experimenter);
    1550           0 :         swofp_flow_entry_table_free((struct ofp_instruction **)
    1551           0 :             &swfe->swfe_meter);
    1552           0 : }
    1553             : 
    1554             : void
    1555           0 : swofp_flow_entry_free(struct swofp_flow_entry **swfe)
    1556             : {
    1557           0 :         if ((*swfe)->swfe_match)
    1558           0 :                 free((*swfe)->swfe_match, M_DEVBUF,
    1559           0 :                     ntohs((*swfe)->swfe_match->om_length));
    1560             : 
    1561           0 :         swofp_flow_entry_instruction_free(*swfe);
    1562             : 
    1563           0 :         free((*swfe), M_DEVBUF, sizeof(**swfe));
    1564           0 : }
    1565             : 
    1566             : void
    1567           0 : swofp_flow_entry_add(struct switch_softc *sc, struct swofp_flow_table *swft,
    1568             :     struct swofp_flow_entry *swfe)
    1569             : {
    1570           0 :         swfe->swfe_table_id = swft->swft_table_id;
    1571           0 :         LIST_INSERT_HEAD(&swft->swft_flow_list, swfe, swfe_next);
    1572           0 :         swft->swft_flow_num++;
    1573             : 
    1574             :         DPRINTF(sc, "add flow in table %d (total %d)\n",
    1575             :             swft->swft_table_id, swft->swft_flow_num);
    1576           0 : }
    1577             : 
    1578             : void
    1579           0 : swofp_flow_entry_delete(struct switch_softc *sc, struct swofp_flow_table *swft,
    1580             :     struct swofp_flow_entry *swfe, uint8_t reason)
    1581             : {
    1582           0 :         if (swfe->swfe_flags & OFP_FLOWFLAG_SEND_FLOW_REMOVED)
    1583           0 :                 swofp_send_flow_removed(sc, swfe, reason);
    1584             : 
    1585           0 :         LIST_REMOVE(swfe, swfe_next);
    1586           0 :         swofp_flow_entry_free(&swfe);
    1587           0 :         swft->swft_flow_num--;
    1588             : 
    1589             :         DPRINTF(sc, "delete flow from table %d (total %d)\n",
    1590             :             swft->swft_table_id, swft->swft_flow_num);
    1591           0 : }
    1592             : 
    1593             : void
    1594           0 : swofp_flow_timeout(struct switch_softc *sc)
    1595             : {
    1596           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    1597             :         struct swofp_flow_table *swft;
    1598             :         struct swofp_flow_entry *swfe, *tswfe;
    1599           0 :         struct timespec          now, duration, idle;
    1600             : 
    1601           0 :         nanouptime(&now);
    1602             : 
    1603           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    1604           0 :                 LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list,
    1605             :                     swfe_next, tswfe) {
    1606           0 :                         if (swfe->swfe_idle_timeout) {
    1607           0 :                                 timespecsub(&now, &swfe->swfe_idle_time, &idle);
    1608           0 :                                 if (swfe->swfe_idle_timeout < idle.tv_sec) {
    1609             :                                         DPRINTF(sc, "flow expired "
    1610             :                                             "by idle timeout\n");
    1611           0 :                                         swofp_flow_entry_delete(sc, swft, swfe,
    1612             :                                             OFP_FLOWREM_REASON_IDLE_TIMEOUT);
    1613           0 :                                         continue;
    1614             :                                 }
    1615             :                         }
    1616           0 :                         if (swfe->swfe_hard_timeout) {
    1617           0 :                                 timespecsub(&now, &swfe->swfe_installed_time,
    1618             :                                     &duration);
    1619           0 :                                 if (swfe->swfe_hard_timeout < duration.tv_sec) {
    1620             :                                         DPRINTF(sc, "flow expired "
    1621             :                                             "by hard timeout\n");
    1622           0 :                                         swofp_flow_entry_delete(sc, swft, swfe,
    1623             :                                             OFP_FLOWREM_REASON_HARD_TIMEOUT);
    1624           0 :                                 }
    1625             :                         }
    1626             :                 }
    1627             :         }
    1628           0 : }
    1629             : 
    1630             : void
    1631           0 : swofp_timer(void *v)
    1632             : {
    1633           0 :         struct switch_softc     *sc = (struct switch_softc *)v;
    1634           0 :         struct swofp_ofs        *swofs = sc->sc_ofs;
    1635             : 
    1636           0 :         swofp_flow_timeout(sc);
    1637           0 :         timeout_add_sec(&swofs->swofs_flow_timeout, 10);
    1638           0 : }
    1639             : 
    1640             : int
    1641           0 : swofp_ox_cmp_data(struct ofp_ox_match *target,
    1642             :     struct ofp_ox_match *key, int strict)
    1643             : {
    1644           0 :         uint64_t         tmth, tmask, kmth, kmask;
    1645           0 :         uint64_t         dummy_mask = UINT64_MAX;
    1646             :         int              len;
    1647             : 
    1648           0 :         if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
    1649           0 :                 return (1);
    1650             : 
    1651           0 :         switch (OFP_OXM_GET_FIELD(target)) {
    1652             :         case OFP_XM_T_VLAN_PCP:
    1653             :         case OFP_XM_T_IP_DSCP:
    1654             :         case OFP_XM_T_IP_ECN:
    1655             :         case OFP_XM_T_IP_PROTO:
    1656             :         case OFP_XM_T_ICMPV4_CODE:
    1657             :         case OFP_XM_T_ICMPV4_TYPE:
    1658             :         case OFP_XM_T_ICMPV6_CODE:
    1659             :         case OFP_XM_T_ICMPV6_TYPE:
    1660             :                 len = sizeof(uint8_t);
    1661           0 :                 break;
    1662             :         case OFP_XM_T_ETH_TYPE:
    1663             :         case OFP_XM_T_TCP_SRC:
    1664             :         case OFP_XM_T_TCP_DST:
    1665             :         case OFP_XM_T_UDP_SRC:
    1666             :         case OFP_XM_T_UDP_DST:
    1667             :         case OFP_XM_T_ARP_OP:
    1668             :                 len = sizeof(uint16_t);
    1669           0 :                 break;
    1670             :         case OFP_XM_T_IN_PORT:
    1671             :         case OFP_XM_T_IPV6_FLABEL:
    1672             :                 len = sizeof(uint32_t);
    1673           0 :                 break;
    1674             :         case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */
    1675             :                 len = sizeof(uint64_t);
    1676           0 :                 break;
    1677             :         default:
    1678           0 :                 return (1);
    1679             :         }
    1680             : 
    1681           0 :         tmth = tmask = kmth = kmask = 0;
    1682             : 
    1683           0 :         memcpy(&tmth, ((caddr_t)target + sizeof(*target)), len);
    1684           0 :         if (OFP_OXM_GET_HASMASK(target))
    1685           0 :                 memcpy(&tmask, ((caddr_t)target + sizeof(*target) + len), len);
    1686             :         else
    1687           0 :                 memcpy(&tmask, &dummy_mask, len);
    1688             : 
    1689           0 :         memcpy(&kmth, ((caddr_t)key + sizeof(*key)), len);
    1690           0 :         if (OFP_OXM_GET_HASMASK(key))
    1691           0 :                 memcpy(&kmask, ((caddr_t)key + sizeof(*key) + len), len);
    1692             :         else
    1693           0 :                 memcpy(&kmask, &dummy_mask, len);
    1694             : 
    1695           0 :         if (strict) {
    1696           0 :                 if (tmask != kmask)
    1697           0 :                         return (1);
    1698             :         } else {
    1699           0 :                 if ((tmask & kmask) != kmask)
    1700           0 :                         return (1);
    1701             :         }
    1702             : 
    1703           0 :         return !((tmth & tmask) == (kmth & kmask));
    1704           0 : }
    1705             : 
    1706             : #ifdef INET6
    1707             : int
    1708           0 : swofp_ox_cmp_ipv6_addr(struct ofp_ox_match *target,
    1709             :     struct ofp_ox_match *key, int strict)
    1710             : {
    1711           0 :         struct in6_addr tmth, tmask, kmth, kmask;
    1712           0 :         struct in6_addr mask = in6mask128;
    1713             : 
    1714           0 :         if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
    1715           0 :                 return (1);
    1716             : 
    1717           0 :         switch (OFP_OXM_GET_FIELD(target)) {
    1718             :         case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
    1719             :         case OFP_XM_NXMT_TUNNEL_IPV6_DST:
    1720             :         case OFP_XM_T_IPV6_SRC:
    1721             :         case OFP_XM_T_IPV6_DST:
    1722             :         case OFP_XM_T_IPV6_ND_TARGET:
    1723             :                 break;
    1724             :         default:
    1725           0 :                 return (1);
    1726             :         }
    1727             : 
    1728           0 :         memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(kmth));
    1729           0 :         if (OFP_OXM_GET_HASMASK(key))
    1730           0 :                 memcpy(&kmask, ((caddr_t)key + sizeof(*key) + sizeof(kmask)),
    1731             :                     sizeof(kmask));
    1732             :         else
    1733           0 :                 kmask = mask;
    1734             : 
    1735           0 :         memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(tmth));
    1736           0 :         if (OFP_OXM_GET_HASMASK(target))
    1737           0 :                 memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
    1738             :                     sizeof(tmask)), sizeof(tmask));
    1739             :         else
    1740           0 :                 tmask = mask;
    1741             : 
    1742           0 :         if (strict) {
    1743           0 :                 if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0)
    1744           0 :                         return (1);
    1745             : 
    1746           0 :                 tmth.s6_addr32[0] &= tmask.s6_addr32[0];
    1747           0 :                 tmth.s6_addr32[1] &= tmask.s6_addr32[1];
    1748           0 :                 tmth.s6_addr32[2] &= tmask.s6_addr32[2];
    1749           0 :                 tmth.s6_addr32[3] &= tmask.s6_addr32[3];
    1750             : 
    1751           0 :                 kmth.s6_addr32[0] &= kmask.s6_addr32[0];
    1752           0 :                 kmth.s6_addr32[1] &= kmask.s6_addr32[1];
    1753           0 :                 kmth.s6_addr32[2] &= kmask.s6_addr32[2];
    1754           0 :                 kmth.s6_addr32[3] &= kmask.s6_addr32[3];
    1755             : 
    1756           0 :         } else {
    1757           0 :                 tmask.s6_addr32[0] &= kmask.s6_addr32[0];
    1758           0 :                 tmask.s6_addr32[1] &= kmask.s6_addr32[1];
    1759           0 :                 tmask.s6_addr32[2] &= kmask.s6_addr32[2];
    1760           0 :                 tmask.s6_addr32[3] &= kmask.s6_addr32[3];
    1761             : 
    1762           0 :                 if (memcmp(&tmask, &kmask, sizeof(tmask)) != 0)
    1763           0 :                         return (1);
    1764             : 
    1765           0 :                 tmth.s6_addr32[0] &= kmask.s6_addr32[0];
    1766           0 :                 tmth.s6_addr32[1] &= kmask.s6_addr32[1];
    1767           0 :                 tmth.s6_addr32[2] &= kmask.s6_addr32[2];
    1768           0 :                 tmth.s6_addr32[3] &= kmask.s6_addr32[3];
    1769             : 
    1770           0 :                 kmth.s6_addr32[0] &= kmask.s6_addr32[0];
    1771           0 :                 kmth.s6_addr32[1] &= kmask.s6_addr32[1];
    1772           0 :                 kmth.s6_addr32[2] &= kmask.s6_addr32[2];
    1773           0 :                 kmth.s6_addr32[3] &= kmask.s6_addr32[3];
    1774             : 
    1775             :         }
    1776             : 
    1777           0 :         return memcmp(&tmth, &kmth, sizeof(tmth));
    1778           0 : }
    1779             : #endif /* INET6 */
    1780             : 
    1781             : int
    1782           0 : swofp_ox_cmp_ipv4_addr(struct ofp_ox_match *target,
    1783             :     struct ofp_ox_match *key, int strict)
    1784             : {
    1785             :         uint32_t        tmth, tmask, kmth, kmask;
    1786             : 
    1787           0 :         if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
    1788           0 :                 return (1);
    1789             : 
    1790           0 :         switch (OFP_OXM_GET_FIELD(target)) {
    1791             :         case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
    1792             :         case OFP_XM_NXMT_TUNNEL_IPV4_DST:
    1793             :         case OFP_XM_T_IPV4_SRC:
    1794             :         case OFP_XM_T_IPV4_DST:
    1795             :         case OFP_XM_T_ARP_SPA:
    1796             :         case OFP_XM_T_ARP_TPA:
    1797             :                 break;
    1798             :         default:
    1799           0 :                 return (1);
    1800             :         }
    1801             : 
    1802           0 :         memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint32_t));
    1803           0 :         if (OFP_OXM_GET_HASMASK(target))
    1804           0 :                 memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
    1805             :                     sizeof(uint32_t)), sizeof(uint32_t));
    1806             :         else
    1807             :                 tmask = UINT32_MAX;
    1808             : 
    1809           0 :         memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint32_t));
    1810           0 :         if (OFP_OXM_GET_HASMASK(key))
    1811           0 :                 memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
    1812             :                     sizeof(uint32_t)), sizeof(uint32_t));
    1813             :         else
    1814             :                 kmask = UINT32_MAX;
    1815             : 
    1816           0 :         if (strict) {
    1817           0 :                 if (tmask != kmask)
    1818           0 :                         return (1);
    1819             :         } else {
    1820           0 :                 if ((tmask & kmask) != kmask)
    1821           0 :                         return (1);
    1822             :         }
    1823             : 
    1824           0 :         return !((tmth & kmask) == (kmth & kmask));
    1825           0 : }
    1826             : 
    1827             : int
    1828           0 : swofp_ox_cmp_vlan_vid(struct ofp_ox_match *target,
    1829             :     struct ofp_ox_match *key, int strict)
    1830             : {
    1831             :         uint16_t tmth, tmask, kmth, kmask;
    1832             : 
    1833           0 :         if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key) ||
    1834           0 :             OFP_OXM_GET_FIELD(target) != OFP_XM_T_VLAN_VID)
    1835           0 :                 return (1);
    1836             : 
    1837           0 :         memcpy(&tmth, ((caddr_t)target + sizeof(*target)), sizeof(uint16_t));
    1838           0 :         if (OFP_OXM_GET_HASMASK(target))
    1839           0 :                 memcpy(&tmask, ((caddr_t)target + sizeof(*target)
    1840             :                     + sizeof(uint16_t)), sizeof(uint16_t));
    1841             :         else
    1842             :                 tmask = UINT16_MAX;
    1843             : 
    1844           0 :         memcpy(&kmth, ((caddr_t)key + sizeof(*key)), sizeof(uint16_t));
    1845           0 :         if (OFP_OXM_GET_HASMASK(key))
    1846           0 :                 memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
    1847             :                     sizeof(uint16_t)), sizeof(uint16_t));
    1848             :         else
    1849             :                 kmask = UINT16_MAX;
    1850             : 
    1851           0 :         tmth &= htons(EVL_VLID_MASK);
    1852           0 :         tmask &= htons(EVL_VLID_MASK);
    1853           0 :         kmth &= htons(EVL_VLID_MASK);
    1854           0 :         kmask &= htons(EVL_VLID_MASK);
    1855             : 
    1856           0 :         if (strict) {
    1857           0 :                 if (tmask != kmask)
    1858           0 :                         return (1);
    1859             :         } else {
    1860           0 :                 if ((tmask & kmask) != kmask)
    1861           0 :                         return (1);
    1862             :         }
    1863             : 
    1864           0 :         return !((tmth & kmask) == (kmth & kmask));
    1865           0 : }
    1866             : 
    1867             : int
    1868           0 : swofp_ox_cmp_ether_addr(struct ofp_ox_match *target,
    1869             :     struct ofp_ox_match *key, int strict)
    1870             : {
    1871             :         uint64_t         tmth, tmask, kmth, kmask;
    1872             :         uint64_t         eth_mask = 0x0000FFFFFFFFFFFFULL;
    1873             : 
    1874             : 
    1875           0 :         if (OFP_OXM_GET_FIELD(target) != OFP_OXM_GET_FIELD(key))
    1876           0 :                 return (1);
    1877             : 
    1878           0 :         switch (OFP_OXM_GET_FIELD(target)) {
    1879             :         case OFP_XM_T_ETH_SRC:
    1880             :         case OFP_XM_T_ETH_DST:
    1881             :         case OFP_XM_T_ARP_SHA:
    1882             :         case OFP_XM_T_ARP_THA:
    1883             :         case OFP_XM_T_IPV6_ND_SLL:
    1884             :         case OFP_XM_T_IPV6_ND_TLL:
    1885             :                 break;
    1886             :         default:
    1887           0 :                 return (1);
    1888             :         }
    1889             : 
    1890           0 :         memcpy(&tmth, ((caddr_t)target + sizeof(*target)), ETHER_ADDR_LEN);
    1891           0 :         if (OFP_OXM_GET_HASMASK(target))
    1892           0 :                 memcpy(&tmask, ((caddr_t)target + sizeof(*target) +
    1893             :                     ETHER_ADDR_LEN), ETHER_ADDR_LEN);
    1894             :         else
    1895             :                 tmask = UINT64_MAX;
    1896             : 
    1897           0 :         memcpy(&kmth, ((caddr_t)key + sizeof(*key)), ETHER_ADDR_LEN);
    1898           0 :         if (OFP_OXM_GET_HASMASK(key))
    1899           0 :                 memcpy(&kmask, ((caddr_t)key + sizeof(*key) +
    1900             :                     ETHER_ADDR_LEN), ETHER_ADDR_LEN);
    1901             :         else
    1902             :                 kmask = UINT64_MAX;
    1903             : 
    1904           0 :         tmask &= eth_mask;
    1905           0 :         tmth &= eth_mask;
    1906           0 :         kmask &= eth_mask;
    1907           0 :         kmth &= eth_mask;
    1908             : 
    1909           0 :         if (strict) {
    1910           0 :                 if (tmask != kmask)
    1911           0 :                         return (1);
    1912             :         } else {
    1913           0 :                 if ((tmask & kmask) != kmask)
    1914           0 :                         return (1);
    1915             :         }
    1916             : 
    1917           0 :         return !((tmth & kmask) == (kmth & kmask));
    1918           0 : }
    1919             : 
    1920             : int
    1921           0 : swofp_validate_oxm(struct ofp_ox_match *oxm, uint16_t *err)
    1922             : {
    1923             :         struct ofp_oxm_class    *handler;
    1924             :         int                      hasmask;
    1925             :         int                      neededlen;
    1926             : 
    1927           0 :         handler = swofp_lookup_oxm_handler(oxm);
    1928           0 :         if (handler == NULL || handler->oxm_match == NULL) {
    1929           0 :                 *err = OFP_ERRMATCH_BAD_FIELD;
    1930           0 :                 return (-1);
    1931             :         }
    1932             : 
    1933           0 :         hasmask = OFP_OXM_GET_HASMASK(oxm);
    1934             : 
    1935           0 :         neededlen = (hasmask) ?
    1936           0 :             (handler->oxm_len * 2) : (handler->oxm_len);
    1937           0 :         if (oxm->oxm_length != neededlen) {
    1938           0 :                 *err = OFP_ERRMATCH_BAD_LEN;
    1939           0 :                 return (-1);
    1940             :         }
    1941             : 
    1942           0 :         return (0);
    1943           0 : }
    1944             : 
    1945             : int
    1946           0 : swofp_validate_flow_match(struct ofp_match *om, uint16_t *err)
    1947             : {
    1948             :         struct ofp_ox_match *oxm;
    1949             : 
    1950             :         /*
    1951             :          * TODO this function is missing checks for:
    1952             :          * - OFP_ERRMATCH_BAD_TAG;
    1953             :          * - OFP_ERRMATCH_BAD_VALUE;
    1954             :          * - OFP_ERRMATCH_BAD_MASK;
    1955             :          * - OFP_ERRMATCH_BAD_PREREQ;
    1956             :          * - OFP_ERRMATCH_DUP_FIELD;
    1957             :          */
    1958           0 :         OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) {
    1959           0 :                 if (swofp_validate_oxm(oxm, err))
    1960           0 :                         return (*err);
    1961             :         }
    1962             : 
    1963           0 :         return (0);
    1964           0 : }
    1965             : 
    1966             : int
    1967           0 : swofp_validate_flow_instruction(struct switch_softc *sc,
    1968             :     struct ofp_instruction *oi, size_t total, uint16_t *etype,
    1969             :     uint16_t *err)
    1970             : {
    1971             :         struct ofp_action_header        *oah;
    1972             :         struct ofp_instruction_actions  *oia;
    1973             :         int                              ilen;
    1974             : 
    1975           0 :         *etype = OFP_ERRTYPE_BAD_INSTRUCTION;
    1976             : 
    1977           0 :         ilen = ntohs(oi->i_len);
    1978             :         /* Check for bigger than packet or smaller than header. */
    1979           0 :         if (ilen > total || ilen < sizeof(*oi)) {
    1980           0 :                 *err = OFP_ERRINST_BAD_LEN;
    1981           0 :                 return (-1);
    1982             :         }
    1983             : 
    1984           0 :         switch (ntohs(oi->i_type)) {
    1985             :         case OFP_INSTRUCTION_T_GOTO_TABLE:
    1986           0 :                 if (ilen != sizeof(struct ofp_instruction_goto_table)) {
    1987           0 :                         *err = OFP_ERRINST_BAD_LEN;
    1988           0 :                         return (-1);
    1989             :                 }
    1990             :                 break;
    1991             :         case OFP_INSTRUCTION_T_WRITE_META:
    1992           0 :                 if (ilen != sizeof(struct ofp_instruction_write_metadata)) {
    1993           0 :                         *err = OFP_ERRINST_BAD_LEN;
    1994           0 :                         return (-1);
    1995             :                 }
    1996             :                 break;
    1997             :         case OFP_INSTRUCTION_T_METER:
    1998           0 :                 if (ilen != sizeof(struct ofp_instruction_meter)) {
    1999           0 :                         *err = OFP_ERRINST_BAD_LEN;
    2000           0 :                         return (-1);
    2001             :                 }
    2002             :                 break;
    2003             : 
    2004             :         case OFP_INSTRUCTION_T_WRITE_ACTIONS:
    2005             :         case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
    2006             :         case OFP_INSTRUCTION_T_APPLY_ACTIONS:
    2007           0 :                 if (ilen < sizeof(*oia)) {
    2008           0 :                         *err = OFP_ERRINST_BAD_LEN;
    2009           0 :                         return (-1);
    2010             :                 }
    2011             : 
    2012           0 :                 oia = (struct ofp_instruction_actions *)oi;
    2013             : 
    2014             :                 /* Validate actions before iterating over them. */
    2015           0 :                 oah = (struct ofp_action_header *)
    2016           0 :                     ((uint8_t *)oia + sizeof(*oia));
    2017           0 :                 if (swofp_validate_action(sc, oah, ilen - sizeof(*oia),
    2018             :                     err)) {
    2019           0 :                         *etype = OFP_ERRTYPE_BAD_ACTION;
    2020           0 :                         return (-1);
    2021             :                 }
    2022             :                 break;
    2023             : 
    2024             :         case OFP_INSTRUCTION_T_EXPERIMENTER:
    2025             :                 /* FALLTHROUGH */
    2026             :         default:
    2027           0 :                 *err = OFP_ERRINST_UNKNOWN_INST;
    2028           0 :                 return (-1);
    2029             :         }
    2030             : 
    2031           0 :         return (0);
    2032           0 : }
    2033             : 
    2034             : int
    2035           0 : swofp_validate_action(struct switch_softc *sc, struct ofp_action_header *ah,
    2036             :     size_t ahtotal, uint16_t *err)
    2037             : {
    2038             :         struct ofp_action_handler       *oah;
    2039             :         struct ofp_ox_match             *oxm;
    2040             :         struct ofp_action_push          *ap;
    2041             :         struct ofp_action_group         *ag;
    2042             :         struct ofp_action_output        *ao;
    2043             :         struct switch_port              *swpo;
    2044             :         uint8_t                         *dptr;
    2045             :         int                              ahtype, ahlen, oxmlen;
    2046             : 
    2047             :         /* No actions. */
    2048           0 :         if (ahtotal == 0)
    2049           0 :                 return (0);
    2050             : 
    2051             :         /* Check if we have at least the first header. */
    2052           0 :         if (ahtotal < sizeof(*ah)) {
    2053           0 :                 *err = OFP_ERRACTION_LEN;
    2054           0 :                 return (-1);
    2055             :         }
    2056             : 
    2057             :  parse_next_action:
    2058           0 :         ahtype = ntohs(ah->ah_type);
    2059           0 :         ahlen = ntohs(ah->ah_len);
    2060           0 :         if (ahlen < sizeof(*ah) || ahlen > ahtotal) {
    2061           0 :                 *err = OFP_ERRACTION_LEN;
    2062           0 :                 return (-1);
    2063             :         }
    2064             : 
    2065           0 :         switch (ahtype) {
    2066             :         case OFP_ACTION_OUTPUT:
    2067           0 :                 if (ahlen != sizeof(struct ofp_action_output)) {
    2068           0 :                         *err = OFP_ERRACTION_LEN;
    2069           0 :                         return (-1);
    2070             :                 }
    2071             : 
    2072           0 :                 ao = (struct ofp_action_output *)ah;
    2073           0 :                 switch (ntohl(ao->ao_port)) {
    2074             :                 case OFP_PORT_ANY:
    2075           0 :                         *err = OFP_ERRACTION_OUT_PORT;
    2076           0 :                         return (-1);
    2077             : 
    2078             :                 case OFP_PORT_ALL:
    2079             :                 case OFP_PORT_NORMAL:
    2080             :                         /* TODO implement port ALL and NORMAL. */
    2081           0 :                         *err = OFP_ERRACTION_OUT_PORT;
    2082           0 :                         return (-1);
    2083             : 
    2084             :                 case OFP_PORT_CONTROLLER:
    2085             :                 case OFP_PORT_FLOWTABLE:
    2086             :                 case OFP_PORT_FLOOD:
    2087             :                 case OFP_PORT_INPUT:
    2088             :                 case OFP_PORT_LOCAL:
    2089             :                         break;
    2090             : 
    2091             :                 default:
    2092           0 :                         TAILQ_FOREACH(swpo, &sc->sc_swpo_list,
    2093             :                             swpo_list_next) {
    2094           0 :                                 if (swpo->swpo_port_no ==
    2095           0 :                                     ntohl(ao->ao_port))
    2096             :                                         break;
    2097             :                         }
    2098           0 :                         if (swpo == NULL) {
    2099           0 :                                 *err = OFP_ERRACTION_OUT_PORT;
    2100           0 :                                 return (-1);
    2101             :                         }
    2102             :                         break;
    2103             :                 }
    2104             :                 break;
    2105             :         case OFP_ACTION_GROUP:
    2106           0 :                 if (ahlen != sizeof(struct ofp_action_group)) {
    2107           0 :                         *err = OFP_ERRACTION_LEN;
    2108           0 :                         return (-1);
    2109             :                 }
    2110             : 
    2111           0 :                 ag = (struct ofp_action_group *)ah;
    2112           0 :                 if (swofp_group_entry_lookup(sc,
    2113           0 :                     ntohl(ag->ag_group_id)) == NULL) {
    2114           0 :                         *err = OFP_ERRACTION_BAD_OUT_GROUP;
    2115           0 :                         return (-1);
    2116             :                 }
    2117             :                 break;
    2118             :         case OFP_ACTION_SET_QUEUE:
    2119           0 :                 if (ahlen != sizeof(struct ofp_action_set_queue)) {
    2120           0 :                         *err = OFP_ERRACTION_LEN;
    2121           0 :                         return (-1);
    2122             :                 }
    2123             :                 break;
    2124             :         case OFP_ACTION_SET_MPLS_TTL:
    2125           0 :                 if (ahlen != sizeof(struct ofp_action_mpls_ttl)) {
    2126           0 :                         *err = OFP_ERRACTION_LEN;
    2127           0 :                         return (-1);
    2128             :                 }
    2129             :                 break;
    2130             :         case OFP_ACTION_SET_NW_TTL:
    2131           0 :                 if (ahlen != sizeof(struct ofp_action_nw_ttl)) {
    2132           0 :                         *err = OFP_ERRACTION_LEN;
    2133           0 :                         return (-1);
    2134             :                 }
    2135             :                 break;
    2136             :         case OFP_ACTION_COPY_TTL_OUT:
    2137             :         case OFP_ACTION_COPY_TTL_IN:
    2138             :         case OFP_ACTION_DEC_MPLS_TTL:
    2139             :         case OFP_ACTION_POP_VLAN:
    2140           0 :                 if (ahlen != sizeof(struct ofp_action_header)) {
    2141           0 :                         *err = OFP_ERRACTION_LEN;
    2142           0 :                         return (-1);
    2143             :                 }
    2144             :                 break;
    2145             :         case OFP_ACTION_PUSH_VLAN:
    2146             :         case OFP_ACTION_PUSH_MPLS:
    2147             :         case OFP_ACTION_PUSH_PBB:
    2148           0 :                 if (ahlen != sizeof(struct ofp_action_push)) {
    2149           0 :                         *err = OFP_ERRACTION_LEN;
    2150           0 :                         return (-1);
    2151             :                 }
    2152             : 
    2153           0 :                 ap = (struct ofp_action_push *)ah;
    2154           0 :                 switch (ntohs(ap->ap_type)) {
    2155             :                 case OFP_ACTION_PUSH_VLAN:
    2156           0 :                         if (ntohs(ap->ap_ethertype) != ETHERTYPE_VLAN &&
    2157           0 :                             ntohs(ap->ap_ethertype) != ETHERTYPE_QINQ) {
    2158           0 :                                 *err = OFP_ERRACTION_ARGUMENT;
    2159           0 :                                 return (-1);
    2160             :                         }
    2161             :                         break;
    2162             : 
    2163             :                 case OFP_ACTION_PUSH_MPLS:
    2164             :                 case OFP_ACTION_PUSH_PBB:
    2165             :                         /* Not implemented yet. */
    2166             :                 default:
    2167           0 :                         *err = OFP_ERRACTION_TYPE;
    2168           0 :                         return (-1);
    2169             :                 }
    2170             :                 break;
    2171             :         case OFP_ACTION_POP_MPLS:
    2172           0 :                 if (ahlen != sizeof(struct ofp_action_pop_mpls)) {
    2173           0 :                         *err = OFP_ERRACTION_LEN;
    2174           0 :                         return (-1);
    2175             :                 }
    2176             :                 break;
    2177             :         case OFP_ACTION_SET_FIELD:
    2178           0 :                 if (ahlen < sizeof(struct ofp_action_set_field)) {
    2179           0 :                         *err = OFP_ERRACTION_LEN;
    2180           0 :                         return (-1);
    2181             :                 }
    2182             : 
    2183           0 :                 oxmlen = ahlen - (sizeof(struct ofp_action_set_field) -
    2184             :                     offsetof(struct ofp_action_set_field, asf_field));
    2185           0 :                 if (oxmlen < sizeof(*oxm)) {
    2186           0 :                         *err = OFP_ERRACTION_LEN;
    2187           0 :                         return (-1);
    2188             :                 }
    2189             : 
    2190           0 :                 dptr = (uint8_t *)ah;
    2191           0 :                 dptr += sizeof(struct ofp_action_set_field) -
    2192             :                     offsetof(struct ofp_action_set_field, asf_field);
    2193           0 :                 while (oxmlen > 0) {
    2194           0 :                         oxm = (struct ofp_ox_match *)dptr;
    2195           0 :                         if (swofp_validate_oxm(oxm, err)) {
    2196           0 :                                 if (*err == OFP_ERRMATCH_BAD_LEN)
    2197           0 :                                         *err = OFP_ERRACTION_SET_LEN;
    2198             :                                 else
    2199           0 :                                         *err = OFP_ERRACTION_SET_TYPE;
    2200             : 
    2201           0 :                                 return (-1);
    2202             :                         }
    2203             : 
    2204           0 :                         dptr += sizeof(*oxm) + oxm->oxm_length;
    2205           0 :                         oxmlen -= sizeof(*oxm) + oxm->oxm_length;
    2206             :                 }
    2207             :                 break;
    2208             : 
    2209             :         default:
    2210             :                 /* Unknown/unsupported action. */
    2211           0 :                 *err = OFP_ERRACTION_TYPE;
    2212           0 :                 return (-1);
    2213             :         }
    2214             : 
    2215           0 :         oah = swofp_lookup_action_handler(ahtype);
    2216             :         /* Unknown/unsupported action. */
    2217           0 :         if (oah == NULL) {
    2218           0 :                 *err = OFP_ERRACTION_TYPE;
    2219           0 :                 return (-1);
    2220             :         }
    2221             : 
    2222           0 :         ahtotal -= min(ahlen, ahtotal);
    2223           0 :         if (ahtotal) {
    2224           0 :                 ah = (struct ofp_action_header *)((uint8_t *)ah + ahlen);
    2225           0 :                 goto parse_next_action;
    2226             :         }
    2227             : 
    2228           0 :         return (0);
    2229           0 : }
    2230             : 
    2231             : int
    2232           0 : swofp_flow_filter_out_port(struct ofp_instruction_actions *oia,
    2233             :     uint32_t out_port)
    2234             : {
    2235             :         struct ofp_action_header        *oah;
    2236             :         struct ofp_action_output        *oao;
    2237             : 
    2238           0 :         if (oia == NULL)
    2239           0 :                 return (0);
    2240             : 
    2241           0 :         OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) {
    2242           0 :                 if (ntohs(oah->ah_type) == OFP_ACTION_OUTPUT) {
    2243           0 :                         oao = (struct ofp_action_output *)oah;
    2244           0 :                         if (ntohl(oao->ao_port) == out_port)
    2245           0 :                                 return (1);
    2246             :                 }
    2247             :         }
    2248             : 
    2249           0 :         return (0);
    2250           0 : }
    2251             : 
    2252             : int
    2253           0 : swofp_flow_filter(struct swofp_flow_entry *swfe, uint64_t cookie,
    2254             :     uint64_t cookie_mask, uint32_t out_port, uint32_t out_group)
    2255             : {
    2256             : 
    2257           0 :         if (cookie_mask != 0 &&
    2258           0 :             ((swfe->swfe_cookie & cookie_mask) != (cookie & cookie_mask)))
    2259           0 :                 return (0);
    2260             : 
    2261           0 :         if ((out_port == OFP_PORT_ANY) && (out_group == OFP_GROUP_ID_ALL))
    2262           0 :                 return (1);
    2263             : 
    2264           0 :         if ((out_port != OFP_PORT_ANY) &&
    2265           0 :             !(swofp_flow_filter_out_port(swfe->swfe_write_actions, out_port) ||
    2266           0 :             swofp_flow_filter_out_port(swfe->swfe_apply_actions, out_port)))
    2267           0 :             return (0);
    2268             : 
    2269             :         if (out_port != OFP_GROUP_ID_ALL) {
    2270             :                 /* XXX ignore group */
    2271             :         }
    2272             : 
    2273           0 :         return (1);
    2274           0 : }
    2275             : 
    2276             : int
    2277           0 : swofp_flow_cmp_common(struct swofp_flow_entry *swfe, struct ofp_match *key,
    2278             :     int strict)
    2279             : {
    2280           0 :         struct ofp_match        *target = swfe->swfe_match;
    2281             :         struct ofp_oxm_class    *khandler;
    2282             :         struct ofp_ox_match     *toxm, *koxm;
    2283             :         void                    *kmask;
    2284             :         int                      len;
    2285             :         /* maximam payload size is size of struct in6_addr */
    2286           0 :         uint8_t                  dummy_unmask[sizeof(struct in6_addr)];
    2287             : 
    2288           0 :         memset(dummy_unmask, 0, sizeof(dummy_unmask));
    2289             : 
    2290           0 :         OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm) {
    2291           0 :                 khandler = swofp_lookup_oxm_handler(koxm);
    2292           0 :                 if (khandler == NULL || khandler->oxm_match == NULL)
    2293           0 :                         return (0);
    2294             : 
    2295           0 :                 len = khandler->oxm_len;
    2296             : 
    2297             :                 /*
    2298             :                  * OpenFlow Switch Specification 1.3.5 says:
    2299             :                  *  - An all-zero-bits oxm_mask is equivalent to omitting
    2300             :                  *    the OXM TLV entirely
    2301             :                  */
    2302           0 :                 if (strict && OFP_OXM_GET_HASMASK(koxm)) {
    2303           0 :                         kmask = (void *)((caddr_t)koxm + sizeof(*koxm) + len);
    2304           0 :                         if (memcmp(kmask, dummy_unmask, len) == 0)
    2305             :                                 continue;
    2306             :                 }
    2307             : 
    2308           0 :                 OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm) {
    2309           0 :                         if (khandler->oxm_cmp(toxm, koxm, strict) == 0)
    2310             :                                 break;
    2311             :                 }
    2312           0 :                 if (OFP_OXM_TERMINATED(target, ntohs(target->om_length), toxm))
    2313           0 :                         return (0);
    2314             :         }
    2315             : 
    2316           0 :         return (1);
    2317           0 : }
    2318             : 
    2319             : int
    2320           0 : swofp_flow_cmp_non_strict(struct swofp_flow_entry *swfe, struct ofp_match *key)
    2321             : {
    2322             :         /* Every oxm matching is wildcard */
    2323           0 :         if (key == NULL)
    2324           0 :                 return (1);
    2325             : 
    2326           0 :         return swofp_flow_cmp_common(swfe, key, 0);
    2327           0 : }
    2328             : 
    2329             : int
    2330           0 : swofp_flow_cmp_strict(struct swofp_flow_entry *swfe, struct ofp_match *key,
    2331             :     uint32_t priority)
    2332             : {
    2333           0 :         struct ofp_match        *target = swfe->swfe_match;
    2334             :         struct ofp_ox_match     *toxm, *koxm;
    2335             :         int                      key_matches, target_matches;
    2336             : 
    2337             :         /*
    2338             :          * Both target and key values are put on network byte order,
    2339             :          * so it's ok that those are compared without changing byte order
    2340             :          */
    2341           0 :         if (swfe->swfe_priority != priority)
    2342           0 :                 return (0);
    2343             : 
    2344             :         key_matches = target_matches = 0;
    2345           0 :         OFP_OXM_FOREACH(key, ntohs(key->om_length), koxm)
    2346           0 :                 key_matches++;
    2347             : 
    2348           0 :         OFP_OXM_FOREACH(target, ntohs(target->om_length), toxm)
    2349           0 :                 target_matches++;
    2350             : 
    2351           0 :         if (key_matches != target_matches)
    2352           0 :                 return (0);
    2353             : 
    2354           0 :         return swofp_flow_cmp_common(swfe, key, 1);
    2355           0 : }
    2356             : 
    2357             : struct swofp_flow_entry *
    2358           0 : swofp_flow_search_by_table(struct swofp_flow_table *swft, struct ofp_match *key,
    2359             :     uint16_t priority)
    2360             : {
    2361             :         struct swofp_flow_entry *swfe;
    2362             : 
    2363           0 :         LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
    2364           0 :                 if (swofp_flow_cmp_strict(swfe, key, priority))
    2365           0 :                         return (swfe);
    2366             :         }
    2367             : 
    2368           0 :         return (NULL);
    2369           0 : }
    2370             : 
    2371             : int
    2372           0 : swofp_flow_has_group(struct ofp_instruction_actions *oia, uint32_t group_id)
    2373             : {
    2374             :         struct ofp_action_header        *oah;
    2375             :         struct ofp_action_group         *oag;
    2376             : 
    2377           0 :         if (oia == NULL)
    2378           0 :                 return (0);
    2379             : 
    2380           0 :         OFP_I_ACTIONS_FOREACH((struct ofp_instruction_actions *)oia, oah) {
    2381           0 :                 if (ntohs(oah->ah_type) == OFP_ACTION_GROUP) {
    2382           0 :                         oag = (struct ofp_action_group *)oah;
    2383           0 :                         if (ntohl(oag->ag_group_id) == group_id)
    2384           0 :                                 return (1);
    2385             :                 }
    2386             :         }
    2387             : 
    2388           0 :         return (0);
    2389           0 : }
    2390             : 
    2391             : void
    2392           0 : swofp_flow_delete_on_table_by_group(struct switch_softc *sc,
    2393             :     struct swofp_flow_table *swft, uint32_t group_id)
    2394             : {
    2395             :         struct swofp_flow_entry *swfe, *tswfe;
    2396             : 
    2397           0 :         LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
    2398           0 :                 if (swofp_flow_has_group(swfe->swfe_apply_actions, group_id) ||
    2399           0 :                     swofp_flow_has_group(swfe->swfe_write_actions, group_id)) {
    2400           0 :                         swofp_flow_entry_delete(sc, swft, swfe,
    2401             :                             OFP_FLOWREM_REASON_GROUP_DELETE);
    2402           0 :                 }
    2403             :         }
    2404           0 : }
    2405             : 
    2406             : void
    2407           0 : swofp_flow_delete_on_table(struct switch_softc *sc,
    2408             :     struct swofp_flow_table *swft, struct ofp_match *key, uint16_t priority,
    2409             :     uint64_t cookie, uint64_t cookie_mask, uint32_t out_port,
    2410             :     uint32_t out_group, int strict)
    2411             : {
    2412             :         struct swofp_flow_entry *swfe, *tswfe;
    2413             : 
    2414           0 :         LIST_FOREACH_SAFE(swfe, &swft->swft_flow_list, swfe_next, tswfe) {
    2415           0 :                 if (strict && !swofp_flow_cmp_strict(swfe, key, priority))
    2416             :                         continue;
    2417           0 :                 else if (!swofp_flow_cmp_non_strict(swfe, key))
    2418             :                         continue;
    2419             : 
    2420           0 :                 if (!swofp_flow_filter(swfe, cookie, cookie_mask,
    2421             :                     out_port, out_group))
    2422             :                         continue;
    2423             : 
    2424           0 :                 swofp_flow_entry_delete(sc, swft, swfe,
    2425             :                     OFP_FLOWREM_REASON_DELETE);
    2426           0 :         }
    2427           0 : }
    2428             : 
    2429             : void
    2430           0 : swofp_ox_match_put_start(struct ofp_match *om)
    2431             : {
    2432           0 :         om->om_type = htons(OFP_MATCH_OXM);
    2433           0 :         om->om_length = htons(sizeof(*om));
    2434           0 : }
    2435             : 
    2436             : /*
    2437             :  * Return ofp_match length include "PADDING" byte
    2438             :  */
    2439             : int
    2440           0 : swofp_ox_match_put_end(struct ofp_match *om)
    2441             : {
    2442           0 :         int      tsize = ntohs(om->om_length);
    2443             :         int      padding;
    2444             : 
    2445           0 :         padding = OFP_ALIGN(tsize) - tsize;
    2446           0 :         if (padding)
    2447           0 :                 memset((caddr_t)om + tsize, 0, padding);
    2448             : 
    2449           0 :         return tsize + padding;
    2450             : }
    2451             : 
    2452             : int
    2453           0 : swofp_ox_match_put_uint32(struct ofp_match *om, uint8_t type, uint32_t val)
    2454             : {
    2455           0 :         int      off = ntohs(om->om_length);
    2456             :         struct ofp_ox_match *oxm;
    2457             : 
    2458           0 :         val = htonl(val);
    2459           0 :         oxm = (struct ofp_ox_match *)((caddr_t)om + off);
    2460           0 :         oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
    2461           0 :         OFP_OXM_SET_FIELD(oxm, type);
    2462           0 :         oxm->oxm_length = sizeof(uint32_t);
    2463           0 :         memcpy(oxm->oxm_value, &val, sizeof(val));
    2464           0 :         om->om_length = htons(ntohs(om->om_length) +
    2465             :             sizeof(*oxm) + sizeof(uint32_t));
    2466             : 
    2467           0 :         return ntohs(om->om_length);
    2468             : }
    2469             : 
    2470             : int
    2471           0 : swofp_ox_match_put_uint64(struct ofp_match *om, uint8_t type, uint64_t val)
    2472             : {
    2473             :         struct ofp_ox_match     *oxm;
    2474           0 :         int                      off = ntohs(om->om_length);
    2475             : 
    2476           0 :         val = htobe64(val);
    2477           0 :         oxm = (struct ofp_ox_match *)((caddr_t)om + off);
    2478           0 :         oxm->oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
    2479           0 :         OFP_OXM_SET_FIELD(oxm, type);
    2480           0 :         oxm->oxm_length = sizeof(uint64_t);
    2481           0 :         memcpy(oxm->oxm_value, &val, sizeof(val));
    2482           0 :         om->om_length = htons(ntohs(om->om_length) +
    2483             :             sizeof(*oxm) + sizeof(uint64_t));
    2484             : 
    2485           0 :         return ntohs(om->om_length);
    2486             : }
    2487             : 
    2488             : int
    2489           0 : swofp_nx_match_put(struct ofp_match *om, uint8_t type, int len,
    2490             :     caddr_t val)
    2491             : {
    2492             :         struct ofp_ox_match     *oxm;
    2493           0 :         int                      off = ntohs(om->om_length);
    2494             : 
    2495           0 :         oxm = (struct ofp_ox_match *)((caddr_t)om + off);
    2496           0 :         oxm->oxm_class = htons(OFP_OXM_C_NXM_1);
    2497           0 :         OFP_OXM_SET_FIELD(oxm, type);
    2498           0 :         oxm->oxm_length = len;
    2499           0 :         memcpy((void *)oxm->oxm_value, val, len);
    2500             : 
    2501           0 :         om->om_length = htons(ntohs(om->om_length) + sizeof(*oxm) + len);
    2502             : 
    2503           0 :         return ntohs(om->om_length);
    2504             : }
    2505             : 
    2506             : int
    2507           0 : swofp_ox_set_vlan_vid(struct switch_flow_classify *swfcl,
    2508             :     struct ofp_ox_match *oxm)
    2509             : {
    2510             :         uint16_t         val;
    2511             : 
    2512           0 :         val = *(uint16_t *)oxm->oxm_value;
    2513           0 :         swfcl->swfcl_vlan->vlan_vid = (val & htons(EVL_VLID_MASK));
    2514             : 
    2515           0 :         return (0);
    2516             : }
    2517             : 
    2518             : int
    2519           0 : swofp_ox_set_uint8(struct switch_flow_classify *swfcl,
    2520             :     struct ofp_ox_match *oxm)
    2521             : {
    2522             :         uint8_t          val;
    2523             : 
    2524           0 :         val = *(uint8_t *)oxm->oxm_value;
    2525             : 
    2526           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2527             :         case OFP_XM_T_IP_DSCP:
    2528           0 :                 if (swfcl->swfcl_ipv4)
    2529           0 :                         swfcl->swfcl_ipv4->ipv4_tos = ((val << 2) |
    2530           0 :                             (swfcl->swfcl_ipv4->ipv4_tos & IPTOS_ECN_MASK));
    2531             :                 else
    2532           0 :                         swfcl->swfcl_ipv6->ipv6_tclass = ((val << 2) |
    2533           0 :                             (swfcl->swfcl_ipv6->ipv6_tclass & IPTOS_ECN_MASK));
    2534             :                 break;
    2535             :         case OFP_XM_T_IP_ECN:
    2536           0 :                 if (swfcl->swfcl_ipv4)
    2537           0 :                         swfcl->swfcl_ipv4->ipv4_tos = ((val & IPTOS_ECN_MASK) |
    2538           0 :                             (swfcl->swfcl_ipv4->ipv4_tos & ~IPTOS_ECN_MASK));
    2539             :                 else
    2540           0 :                         swfcl->swfcl_ipv6->ipv6_tclass = (
    2541           0 :                             (val & IPTOS_ECN_MASK) |
    2542           0 :                             (swfcl->swfcl_ipv6->ipv6_tclass & ~IPTOS_ECN_MASK));
    2543             :                 break;
    2544             :         case OFP_XM_T_IP_PROTO:
    2545           0 :                 if (swfcl->swfcl_ipv4)
    2546           0 :                         swfcl->swfcl_ipv4->ipv4_proto = val;
    2547             :                 else
    2548           0 :                         swfcl->swfcl_ipv6->ipv6_nxt = val;
    2549             :                 break;
    2550             :         case OFP_XM_T_ICMPV4_TYPE:
    2551           0 :                 swfcl->swfcl_icmpv4->icmpv4_type = val;
    2552           0 :                 break;
    2553             :         case OFP_XM_T_ICMPV4_CODE:
    2554           0 :                 swfcl->swfcl_icmpv4->icmpv4_code = val;
    2555           0 :                 break;
    2556             :         case OFP_XM_T_ICMPV6_TYPE:
    2557           0 :                 swfcl->swfcl_icmpv6->icmpv6_type = val;
    2558           0 :                 break;
    2559             :         case OFP_XM_T_ICMPV6_CODE:
    2560           0 :                 swfcl->swfcl_icmpv6->icmpv6_code = val;
    2561           0 :                 break;
    2562             :         }
    2563             : 
    2564           0 :         return (0);
    2565             : }
    2566             : 
    2567             : int
    2568           0 : swofp_ox_set_uint16(struct switch_flow_classify *swfcl,
    2569             :     struct ofp_ox_match *oxm)
    2570             : {
    2571             :         uint16_t         val;
    2572             : 
    2573           0 :         val = *(uint16_t *)oxm->oxm_value;
    2574             : 
    2575           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2576             :         case OFP_XM_T_ETH_TYPE:
    2577           0 :                 swfcl->swfcl_ether->eth_type = val;
    2578           0 :                 break;
    2579             :         case OFP_XM_T_VLAN_PCP:
    2580           0 :                 swfcl->swfcl_vlan->vlan_pcp = val;
    2581           0 :                 break;
    2582             :         case OFP_XM_T_TCP_SRC:
    2583           0 :                 swfcl->swfcl_tcp->tcp_src = val;
    2584           0 :                 break;
    2585             :         case OFP_XM_T_TCP_DST:
    2586           0 :                 swfcl->swfcl_tcp->tcp_dst = val;
    2587           0 :                 break;
    2588             :         case OFP_XM_T_UDP_SRC:
    2589           0 :                 swfcl->swfcl_udp->udp_src = val;
    2590           0 :                 break;
    2591             :         case OFP_XM_T_UDP_DST:
    2592           0 :                 swfcl->swfcl_udp->udp_dst = val;
    2593           0 :                 break;
    2594             :         case OFP_XM_T_ARP_OP:
    2595           0 :                 swfcl->swfcl_arp->_arp_op = val;
    2596           0 :         }
    2597             : 
    2598           0 :         return (0);
    2599             : }
    2600             : 
    2601             : int
    2602           0 : swofp_ox_set_uint32(struct switch_flow_classify *swfcl,
    2603             :     struct ofp_ox_match *oxm)
    2604             : {
    2605             :         uint32_t        val;
    2606             : 
    2607           0 :         val = *(uint32_t *)oxm->oxm_value;
    2608             : 
    2609           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2610             :         case OFP_XM_T_IPV6_FLABEL:
    2611           0 :                 swfcl->swfcl_ipv6->ipv6_flow_label = val;
    2612           0 :                 break;
    2613             :         }
    2614             : 
    2615           0 :         return (0);
    2616             : }
    2617             : 
    2618             : int
    2619           0 : swofp_ox_set_uint64(struct switch_flow_classify *swfcl,
    2620             :     struct ofp_ox_match *oxm)
    2621             : {
    2622             :         uint64_t         val;
    2623             : 
    2624           0 :         val = *(uint64_t *)oxm->oxm_value;
    2625             : 
    2626           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2627             :         case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_NXMT_TUNNEL_ID */
    2628           0 :                 swfcl->swfcl_tunnel->tun_key = val;
    2629           0 :                 break;
    2630             :         }
    2631             : 
    2632           0 :         return (0);
    2633             : }
    2634             : 
    2635             : int
    2636           0 : swofp_ox_set_ipv6_addr(struct switch_flow_classify *swfcl,
    2637             :     struct ofp_ox_match *oxm)
    2638             : {
    2639           0 :         struct in6_addr  val;
    2640             : 
    2641           0 :         memcpy(&val, oxm->oxm_value, sizeof(val));
    2642             : 
    2643           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2644             :         case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
    2645           0 :                 swfcl->swfcl_tunnel->tun_ipv6_src = val;
    2646           0 :                 break;
    2647             :         case OFP_XM_NXMT_TUNNEL_IPV6_DST:
    2648           0 :                 swfcl->swfcl_tunnel->tun_ipv6_dst = val;
    2649           0 :                 break;
    2650             :         case OFP_XM_T_IPV6_SRC:
    2651           0 :                 swfcl->swfcl_ipv6->ipv6_src = val;
    2652           0 :                 break;
    2653             :         case OFP_XM_T_IPV6_DST:
    2654           0 :                 swfcl->swfcl_ipv6->ipv6_dst = val;
    2655           0 :                 break;
    2656             :         case OFP_XM_T_IPV6_ND_TARGET:
    2657           0 :                 swfcl->swfcl_nd6->nd6_target = val;
    2658           0 :                 break;
    2659             :         }
    2660             : 
    2661           0 :         return (0);
    2662           0 : }
    2663             : 
    2664             : int
    2665           0 : swofp_ox_set_ipv4_addr(struct switch_flow_classify *swfcl,
    2666             :     struct ofp_ox_match *oxm)
    2667             : {
    2668             :         uint32_t         val;
    2669             : 
    2670           0 :         val = *(uint32_t *)oxm->oxm_value;
    2671             : 
    2672           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2673             :         case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
    2674           0 :                 swfcl->swfcl_tunnel->tun_ipv4_src = *(struct in_addr *)&val;
    2675           0 :                 break;
    2676             :         case OFP_XM_NXMT_TUNNEL_IPV4_DST:
    2677           0 :                 swfcl->swfcl_tunnel->tun_ipv4_dst = *(struct in_addr *)&val;
    2678           0 :                 break;
    2679             :         case OFP_XM_T_IPV4_SRC:
    2680           0 :                 swfcl->swfcl_ipv4->ipv4_src = val;
    2681           0 :                 break;
    2682             :         case OFP_XM_T_IPV4_DST:
    2683           0 :                 swfcl->swfcl_ipv4->ipv4_dst = val;
    2684           0 :                 break;
    2685             :         case OFP_XM_T_ARP_SPA:
    2686           0 :                 swfcl->swfcl_arp->arp_sip = val;
    2687           0 :                 break;
    2688             :         case OFP_XM_T_ARP_TPA:
    2689           0 :                 swfcl->swfcl_arp->arp_tip = val;
    2690           0 :                 break;
    2691             :         }
    2692             : 
    2693           0 :         return (0);
    2694             : }
    2695             : 
    2696             : int
    2697           0 : swofp_ox_set_ether_addr(struct switch_flow_classify *swfcl,
    2698             :     struct ofp_ox_match *oxm)
    2699             : {
    2700             :         caddr_t         eth_addr;
    2701             : 
    2702           0 :         eth_addr = oxm->oxm_value;
    2703             : 
    2704           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2705             :         case OFP_XM_T_ETH_SRC:
    2706           0 :                 memcpy(swfcl->swfcl_ether->eth_src, eth_addr, ETHER_ADDR_LEN);
    2707           0 :                 break;
    2708             :         case OFP_XM_T_ETH_DST:
    2709           0 :                 memcpy(swfcl->swfcl_ether->eth_dst, eth_addr, ETHER_ADDR_LEN);
    2710           0 :                 break;
    2711             :         case OFP_XM_T_ARP_SHA:
    2712           0 :                 memcpy(swfcl->swfcl_arp->arp_sha, eth_addr, ETHER_ADDR_LEN);
    2713           0 :                 break;
    2714             :         case OFP_XM_T_ARP_THA:
    2715           0 :                 memcpy(swfcl->swfcl_arp->arp_tha, eth_addr, ETHER_ADDR_LEN);
    2716           0 :                 break;
    2717             :         case OFP_XM_T_IPV6_ND_TLL:
    2718             :         case OFP_XM_T_IPV6_ND_SLL:
    2719           0 :                 memcpy(swfcl->swfcl_nd6->nd6_lladdr, eth_addr, ETHER_ADDR_LEN);
    2720           0 :                 break;
    2721             :         }
    2722             : 
    2723           0 :         return (0);
    2724             : }
    2725             : 
    2726             : #ifdef INET6
    2727             : int
    2728           0 : swofp_ox_match_ipv6_addr(struct switch_flow_classify *swfcl,
    2729             :     struct ofp_ox_match *oxm)
    2730             : {
    2731           0 :         struct in6_addr  in, mth, mask = in6mask128;
    2732             : 
    2733           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2734             :         case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
    2735             :         case OFP_XM_NXMT_TUNNEL_IPV6_DST:
    2736           0 :                 if (swfcl->swfcl_tunnel == NULL)
    2737           0 :                         return (1);
    2738             :                 break;
    2739             :         case OFP_XM_T_IPV6_SRC:
    2740             :         case OFP_XM_T_IPV6_DST:
    2741           0 :                 if (swfcl->swfcl_ipv6 == NULL)
    2742           0 :                         return (1);
    2743             :                 break;
    2744             :         case OFP_XM_T_IPV6_ND_TARGET:
    2745           0 :                 if (swfcl->swfcl_nd6 == NULL)
    2746           0 :                         return (1);
    2747             :                 break;
    2748             :         default:
    2749           0 :                 return (1);
    2750             :         }
    2751             : 
    2752           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2753             :         case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
    2754           0 :                 in = swfcl->swfcl_tunnel->tun_ipv6_src;
    2755           0 :                 break;
    2756             :         case OFP_XM_NXMT_TUNNEL_IPV6_DST:
    2757           0 :                 in = swfcl->swfcl_tunnel->tun_ipv6_dst;
    2758           0 :                 break;
    2759             :         case OFP_XM_T_IPV6_SRC:
    2760           0 :                 in = swfcl->swfcl_ipv6->ipv6_src;
    2761           0 :                 break;
    2762             :         case OFP_XM_T_IPV6_DST:
    2763           0 :                 in = swfcl->swfcl_ipv6->ipv6_dst;
    2764           0 :                 break;
    2765             :         case OFP_XM_T_IPV6_ND_TARGET:
    2766           0 :                 in = swfcl->swfcl_nd6->nd6_target;
    2767           0 :                 break;
    2768             :         }
    2769             : 
    2770           0 :         memcpy(&mth, oxm->oxm_value, sizeof(mth));
    2771             : 
    2772           0 :         if (OFP_OXM_GET_HASMASK(oxm)) {
    2773           0 :                 memcpy(&mask, oxm->oxm_value + sizeof(mth),
    2774             :                     sizeof(mask));
    2775             : 
    2776           0 :                 in.s6_addr32[0] &= mask.s6_addr32[0];
    2777           0 :                 in.s6_addr32[1] &= mask.s6_addr32[1];
    2778           0 :                 in.s6_addr32[2] &= mask.s6_addr32[2];
    2779           0 :                 in.s6_addr32[3] &= mask.s6_addr32[3];
    2780             : 
    2781           0 :                 mth.s6_addr32[0] &= mask.s6_addr32[0];
    2782           0 :                 mth.s6_addr32[1] &= mask.s6_addr32[1];
    2783           0 :                 mth.s6_addr32[2] &= mask.s6_addr32[2];
    2784           0 :                 mth.s6_addr32[3] &= mask.s6_addr32[3];
    2785           0 :         }
    2786             : 
    2787           0 :         return memcmp(&in, &mth, sizeof(in));
    2788           0 : }
    2789             : #endif /* INET6 */
    2790             : 
    2791             : int
    2792           0 : swofp_ox_match_ipv4_addr(struct switch_flow_classify *swfcl,
    2793             :     struct ofp_ox_match *oxm)
    2794             : {
    2795             :         uint32_t         in, mth, mask;
    2796             : 
    2797           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2798             :         case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
    2799             :         case OFP_XM_NXMT_TUNNEL_IPV4_DST:
    2800           0 :                 if (swfcl->swfcl_tunnel == NULL)
    2801           0 :                         return (1);
    2802             :                 break;
    2803             :         case OFP_XM_T_IPV4_SRC:
    2804             :         case OFP_XM_T_IPV4_DST:
    2805           0 :                 if (swfcl->swfcl_ipv4 == NULL)
    2806           0 :                         return (1);
    2807             :                 break;
    2808             :         case OFP_XM_T_ARP_SPA:
    2809             :         case OFP_XM_T_ARP_TPA:
    2810           0 :                 if (swfcl->swfcl_arp == NULL)
    2811           0 :                         return (1);
    2812             :                 break;
    2813             :         default:
    2814           0 :                 return (1);
    2815             :         }
    2816             : 
    2817           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2818             :         case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
    2819           0 :                 in = swfcl->swfcl_tunnel->tun_ipv4_src.s_addr;
    2820           0 :                 break;
    2821             :         case OFP_XM_NXMT_TUNNEL_IPV4_DST:
    2822           0 :                 in = swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr;
    2823           0 :                 break;
    2824             :         case OFP_XM_T_IPV4_SRC:
    2825           0 :                 in = swfcl->swfcl_ipv4->ipv4_src;
    2826           0 :                 break;
    2827             :         case OFP_XM_T_IPV4_DST:
    2828           0 :                 in = swfcl->swfcl_ipv4->ipv4_dst;
    2829           0 :                 break;
    2830             :         case OFP_XM_T_ARP_SPA:
    2831           0 :                 in = swfcl->swfcl_arp->arp_sip;
    2832           0 :                 break;
    2833             :         case OFP_XM_T_ARP_TPA:
    2834           0 :                 in = swfcl->swfcl_arp->arp_tip;
    2835           0 :                 break;
    2836             :         }
    2837             : 
    2838           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint32_t));
    2839             : 
    2840           0 :         if (OFP_OXM_GET_HASMASK(oxm))
    2841           0 :                 memcpy(&mask, oxm->oxm_value + sizeof(uint32_t),
    2842             :                     sizeof(uint32_t));
    2843             :         else
    2844             :                 mask = UINT32_MAX;
    2845             : 
    2846           0 :         return !((in & mask) == (mth & mask));
    2847           0 : }
    2848             : 
    2849             : int
    2850           0 : swofp_ox_match_vlan_vid(struct switch_flow_classify *swfcl,
    2851             :     struct ofp_ox_match *oxm)
    2852             : {
    2853             :         uint16_t         in, mth, mask = 0;
    2854             : 
    2855           0 :         if (swfcl->swfcl_vlan == NULL)
    2856           0 :                 return (1);
    2857             : 
    2858           0 :         in = swfcl->swfcl_vlan->vlan_vid;
    2859           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint16_t));
    2860             : 
    2861           0 :         if (OFP_OXM_GET_HASMASK(oxm))
    2862           0 :                 memcpy(&mask, oxm->oxm_value + sizeof(uint16_t),
    2863             :                     sizeof(uint16_t));
    2864             :         else
    2865             :                 mask = UINT16_MAX;
    2866             : 
    2867             :         /*
    2868             :          * OpenFlow Switch Specification ver 1.3.5 says if oxm value
    2869             :          * is OFP_XM_VID_NONE, matches only packets without a VLAN tag
    2870             :          */
    2871           0 :         if (mth == htons(OFP_XM_VID_NONE))
    2872           0 :                 return (1);
    2873             : 
    2874             :         /*
    2875             :          * OpenFlow Switch Specification ver 1.3.5 says if oxm value and mask
    2876             :          * is OFP_XM_VID_PRESENT, matches only packets with a VLAN tag
    2877             :          * regardless of its value.
    2878             :          */
    2879           0 :         if (ntohs(mth) == OFP_XM_VID_PRESENT &&
    2880           0 :             ntohs(mask) == OFP_XM_VID_PRESENT)
    2881           0 :                 return (0);
    2882             : 
    2883           0 :         in &= htons(EVL_VLID_MASK);
    2884           0 :         mth &= htons(EVL_VLID_MASK);
    2885             : 
    2886           0 :         return !((in & mask) == (mth & mask));
    2887           0 : }
    2888             : 
    2889             : int
    2890           0 : swofp_ox_match_uint8(struct switch_flow_classify *swfcl,
    2891             :     struct ofp_ox_match *oxm)
    2892             : {
    2893             :         uint8_t          in, mth;
    2894             : 
    2895           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2896             :         case OFP_XM_T_VLAN_PCP:
    2897           0 :                 if (swfcl->swfcl_vlan == NULL)
    2898           0 :                         return (1);
    2899             :                 break;
    2900             :         case OFP_XM_T_IP_DSCP:
    2901             :         case OFP_XM_T_IP_ECN:
    2902             :         case OFP_XM_T_IP_PROTO:
    2903           0 :                 if ((swfcl->swfcl_ipv4 == NULL &&
    2904           0 :                     swfcl->swfcl_ipv6 == NULL))
    2905           0 :                         return (1);
    2906             :                 break;
    2907             :         case OFP_XM_T_ICMPV4_CODE:
    2908             :         case OFP_XM_T_ICMPV4_TYPE:
    2909           0 :                 if (swfcl->swfcl_icmpv4 == NULL)
    2910           0 :                         return (1);
    2911             :                 break;
    2912             :         case OFP_XM_T_ICMPV6_CODE:
    2913             :         case OFP_XM_T_ICMPV6_TYPE:
    2914           0 :                 if (swfcl->swfcl_icmpv6 == NULL)
    2915           0 :                         return (1);
    2916             :                 break;
    2917             :         default:
    2918           0 :                 return (1);
    2919             :         }
    2920             : 
    2921           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2922             :         case OFP_XM_T_VLAN_PCP:
    2923           0 :                 in = swfcl->swfcl_vlan->vlan_pcp;
    2924           0 :                 break;
    2925             :         case OFP_XM_T_IP_DSCP:
    2926           0 :                 if (swfcl->swfcl_ipv4)
    2927           0 :                         in = swfcl->swfcl_ipv4->ipv4_tos >> 2;
    2928             :                 else
    2929           0 :                         in = swfcl->swfcl_ipv6->ipv6_tclass >> 2;
    2930             :                 break;
    2931             :         case OFP_XM_T_IP_ECN:
    2932           0 :                 if (swfcl->swfcl_ipv4)
    2933           0 :                         in = (swfcl->swfcl_ipv4->ipv4_tos) & IPTOS_ECN_MASK;
    2934             :                 else
    2935           0 :                         in = (swfcl->swfcl_ipv6->ipv6_tclass) & IPTOS_ECN_MASK;
    2936             :                 break;
    2937             :         case OFP_XM_T_IP_PROTO:
    2938           0 :                 if (swfcl->swfcl_ipv4)
    2939           0 :                         in = swfcl->swfcl_ipv4->ipv4_proto;
    2940             :                 else
    2941           0 :                         in = swfcl->swfcl_ipv6->ipv6_nxt;
    2942             :                 break;
    2943             :         case OFP_XM_T_ICMPV4_CODE:
    2944           0 :                 in = swfcl->swfcl_icmpv4->icmpv4_code;
    2945           0 :                 break;
    2946             :         case OFP_XM_T_ICMPV4_TYPE:
    2947           0 :                 in = swfcl->swfcl_icmpv4->icmpv4_type;
    2948           0 :                 break;
    2949             :         case OFP_XM_T_ICMPV6_CODE:
    2950           0 :                 in = swfcl->swfcl_icmpv6->icmpv6_code;
    2951           0 :                 break;
    2952             :         case OFP_XM_T_ICMPV6_TYPE:
    2953           0 :                 in = swfcl->swfcl_icmpv6->icmpv6_type;
    2954           0 :                 break;
    2955             :         }
    2956             : 
    2957           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint8_t));
    2958             : 
    2959           0 :         return !(in == mth);
    2960             : 
    2961           0 : }
    2962             : 
    2963             : int
    2964           0 : swofp_ox_match_uint16(struct switch_flow_classify *swfcl,
    2965             :     struct ofp_ox_match *oxm)
    2966             : {
    2967             :         uint16_t         in, mth;
    2968             : 
    2969           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2970             :         case OFP_XM_T_ETH_TYPE:
    2971           0 :                 if (swfcl->swfcl_ether == NULL)
    2972           0 :                         return (1);
    2973             :                 break;
    2974             :         case OFP_XM_T_TCP_SRC:
    2975             :         case OFP_XM_T_TCP_DST:
    2976           0 :                 if (swfcl->swfcl_tcp == NULL)
    2977           0 :                         return (1);
    2978             :                 break;
    2979             :         case OFP_XM_T_UDP_SRC:
    2980             :         case OFP_XM_T_UDP_DST:
    2981           0 :                 if (swfcl->swfcl_udp == NULL)
    2982           0 :                         return (1);
    2983             :                 break;
    2984             :         case OFP_XM_T_ARP_OP:
    2985           0 :                 if (swfcl->swfcl_arp == NULL)
    2986           0 :                         return (1);
    2987             :                 break;
    2988             :         default:
    2989           0 :                 return (1);
    2990             :         }
    2991             : 
    2992           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    2993             :         case OFP_XM_T_ETH_TYPE:
    2994           0 :                 in = swfcl->swfcl_ether->eth_type;
    2995           0 :                 break;
    2996             :         case OFP_XM_T_TCP_SRC:
    2997           0 :                 in = swfcl->swfcl_tcp->tcp_src;
    2998           0 :                 break;
    2999             :         case OFP_XM_T_TCP_DST:
    3000           0 :                 in = swfcl->swfcl_tcp->tcp_dst;
    3001           0 :                 break;
    3002             :         case OFP_XM_T_UDP_SRC:
    3003           0 :                 in = swfcl->swfcl_udp->udp_src;
    3004           0 :                 break;
    3005             :         case OFP_XM_T_UDP_DST:
    3006           0 :                 in = swfcl->swfcl_udp->udp_dst;
    3007           0 :                 break;
    3008             :         case OFP_XM_T_ARP_OP:
    3009           0 :                 in = swfcl->swfcl_arp->_arp_op;
    3010           0 :                 break;
    3011             :         }
    3012             : 
    3013           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint16_t));
    3014             : 
    3015           0 :         return !(in == mth);
    3016           0 : }
    3017             : 
    3018             : int
    3019           0 : swofp_ox_match_uint32(struct switch_flow_classify *swfcl,
    3020             :     struct ofp_ox_match *oxm)
    3021             : {
    3022             :         uint32_t         in, mth, mask, nomask = UINT32_MAX;
    3023             : 
    3024           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3025             :         case OFP_XM_T_IN_PORT:
    3026             :                 /* in_port field is always exist in swfcl */
    3027             :                 break;
    3028             :         case OFP_XM_T_IPV6_FLABEL:
    3029           0 :                 if (swfcl->swfcl_ipv6 == NULL)
    3030           0 :                         return (1);
    3031             :                 break;
    3032             :         default:
    3033           0 :                 return (1);
    3034             :         }
    3035             : 
    3036           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3037             :         case OFP_XM_T_IN_PORT:
    3038             :                 /*
    3039             :                  * in_port isn't network byte order becouse
    3040             :                  * it's pipeline match field.
    3041             :                  */
    3042           0 :                 in = htonl(swfcl->swfcl_in_port);
    3043           0 :                 break;
    3044             :         case OFP_XM_T_IPV6_FLABEL:
    3045           0 :                 in = swfcl->swfcl_ipv6->ipv6_flow_label;
    3046             :                 nomask &= IPV6_FLOWLABEL_MASK;
    3047           0 :                 break;
    3048             :         }
    3049             : 
    3050           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint32_t));
    3051             : 
    3052           0 :         if (OFP_OXM_GET_HASMASK(oxm))
    3053           0 :                 memcpy(&mask, oxm->oxm_value + sizeof(uint32_t),
    3054             :                     sizeof(uint32_t));
    3055             :         else
    3056             :                 mask = nomask;
    3057             : 
    3058           0 :         return !((in & mask) == (mth & mask));
    3059           0 : }
    3060             : 
    3061             : int
    3062           0 : swofp_ox_match_uint64(struct switch_flow_classify *swfcl,
    3063             :     struct ofp_ox_match *oxm)
    3064             : {
    3065             :         uint64_t         in, mth, mask;
    3066             : 
    3067           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3068             :         case OFP_XM_T_META:
    3069             :                 break;
    3070             :         case OFP_XM_T_TUNNEL_ID:
    3071           0 :                 if (swfcl->swfcl_tunnel == NULL)
    3072           0 :                         return (1);
    3073             :                 break;
    3074             :         default:
    3075           0 :                 return (1);
    3076             :         }
    3077             : 
    3078           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3079             :         case OFP_XM_T_META:
    3080           0 :                 in = swfcl->swfcl_metadata;
    3081           0 :                 break;
    3082             :         case OFP_XM_T_TUNNEL_ID:
    3083           0 :                 in = swfcl->swfcl_tunnel->tun_key;
    3084           0 :                 break;
    3085             :         }
    3086             : 
    3087           0 :         memcpy(&mth, oxm->oxm_value, sizeof(uint64_t));
    3088             : 
    3089           0 :         if (OFP_OXM_GET_HASMASK(oxm))
    3090           0 :                 memcpy(&mask, oxm->oxm_value + sizeof(uint64_t),
    3091             :                     sizeof(uint64_t));
    3092             :         else
    3093             :                 mask = UINT64_MAX;
    3094             : 
    3095           0 :         return !((in & mask) == (mth & mask));
    3096           0 : }
    3097             : 
    3098             : int
    3099           0 : swofp_ox_match_ether_addr(struct switch_flow_classify *swfcl,
    3100             :     struct ofp_ox_match *oxm)
    3101             : {
    3102             :         uint64_t         eth_mask = 0x0000FFFFFFFFFFFFULL;
    3103             :         uint64_t         in, mth, mask;
    3104             : 
    3105           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3106             :         case OFP_XM_T_ETH_SRC:
    3107             :         case OFP_XM_T_ETH_DST:
    3108           0 :                 if (swfcl->swfcl_ether == NULL)
    3109           0 :                         return (1);
    3110             :                 break;
    3111             :         case OFP_XM_T_ARP_SHA:
    3112             :         case OFP_XM_T_ARP_THA:
    3113           0 :                 if (swfcl->swfcl_arp == NULL)
    3114           0 :                         return (1);
    3115             :                 break;
    3116             :         case OFP_XM_T_IPV6_ND_SLL:
    3117             :         case OFP_XM_T_IPV6_ND_TLL:
    3118           0 :                 if (swfcl->swfcl_nd6 == NULL)
    3119           0 :                         return (1);
    3120             :                 break;
    3121             :         default:
    3122           0 :                 return (1);
    3123             :         }
    3124             : 
    3125           0 :         switch (OFP_OXM_GET_FIELD(oxm)) {
    3126             :         case OFP_XM_T_ETH_SRC:
    3127           0 :                 in = *(uint64_t *)(swfcl->swfcl_ether->eth_src);
    3128           0 :                 break;
    3129             :         case OFP_XM_T_ETH_DST:
    3130           0 :                 in = *(uint64_t *)(swfcl->swfcl_ether->eth_dst);
    3131           0 :                 break;
    3132             :         case OFP_XM_T_ARP_SHA:
    3133           0 :                 in = *(uint64_t *)(swfcl->swfcl_arp->arp_sha);
    3134           0 :                 break;
    3135             :         case OFP_XM_T_ARP_THA:
    3136           0 :                 in = *(uint64_t *)(swfcl->swfcl_arp->arp_tha);
    3137           0 :                 break;
    3138             :         case OFP_XM_T_IPV6_ND_SLL:
    3139             :         case OFP_XM_T_IPV6_ND_TLL:
    3140           0 :                 in = *(uint64_t *)(swfcl->swfcl_nd6->nd6_lladdr);
    3141           0 :                 break;
    3142             :         }
    3143             : 
    3144           0 :         memcpy(&mth, oxm->oxm_value, ETHER_ADDR_LEN);
    3145           0 :         if (OFP_OXM_GET_HASMASK(oxm))
    3146           0 :                 memcpy(&mask, oxm->oxm_value + ETHER_ADDR_LEN,
    3147             :                     ETHER_ADDR_LEN);
    3148             :         else
    3149             :                 mask = UINT64_MAX;
    3150             : 
    3151           0 :         return !((in & mask & eth_mask) == (mth & mask & eth_mask));
    3152           0 : }
    3153             : 
    3154             : int
    3155           0 : swofp_flow_match_by_swfcl(struct ofp_match *om,
    3156             :     struct switch_flow_classify *swfcl)
    3157             : {
    3158             :         struct ofp_oxm_class    *oxm_handler;
    3159             :         struct ofp_ox_match     *oxm;
    3160             : 
    3161           0 :         OFP_OXM_FOREACH(om, ntohs(om->om_length), oxm) {
    3162           0 :                 oxm_handler = swofp_lookup_oxm_handler(oxm);
    3163           0 :                 if ((oxm_handler == NULL) ||
    3164           0 :                     (oxm_handler->oxm_match == NULL))
    3165             :                         continue;
    3166             : 
    3167           0 :                 if (oxm_handler->oxm_match(swfcl, oxm))
    3168           0 :                         return (1);
    3169             :         }
    3170             : 
    3171           0 :         return (0);
    3172           0 : }
    3173             : 
    3174             : /* TODO: Optimization */
    3175             : struct swofp_flow_entry *
    3176           0 : swofp_flow_lookup(struct swofp_flow_table *swft,
    3177             :     struct switch_flow_classify *swfcl)
    3178             : {
    3179             :         struct swofp_flow_entry *swfe, *interim = NULL;
    3180             : 
    3181           0 :         LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
    3182           0 :                 if (swofp_flow_match_by_swfcl(swfe->swfe_match, swfcl) != 0)
    3183             :                         continue;
    3184             : 
    3185           0 :                 if (interim == NULL ||
    3186           0 :                     (interim->swfe_priority < swfe->swfe_priority))
    3187           0 :                         interim = swfe;
    3188             :         }
    3189             : 
    3190           0 :         swft->swft_lookup_count++;
    3191           0 :         if (interim)
    3192           0 :                 swft->swft_matched_count++;
    3193             : 
    3194           0 :         return interim;
    3195             : }
    3196             : 
    3197             : /*
    3198             :  * OpenFlow protocol push/pop VLAN
    3199             :  */
    3200             : 
    3201             : /* Expand 802.1Q VLAN header from M_VLANTAG mtag if it is exist. */
    3202             : struct mbuf *
    3203           0 : swofp_expand_8021q_tag(struct mbuf *m)
    3204             : {
    3205           0 :         if ((m->m_flags & M_VLANTAG) == 0)
    3206           0 :                 return (m);
    3207             : 
    3208             :         /* H/W tagging supports only 802.1Q */
    3209           0 :         return (vlan_inject(m, ETHERTYPE_VLAN,
    3210           0 :             EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) |
    3211           0 :             EVL_PRIOFTAG(m->m_pkthdr.ether_vtag)));
    3212           0 : }
    3213             : 
    3214             : struct mbuf *
    3215           0 : swofp_action_pop_vlan(struct switch_softc *sc, struct mbuf *m,
    3216             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    3217             : {
    3218           0 :         struct switch_flow_classify     *swfcl = swpld->swpld_swfcl;
    3219             :         struct ether_vlan_header        *evl;
    3220           0 :         struct ether_header              eh;
    3221             : 
    3222             :         /* no vlan tag existing */
    3223           0 :         if (swfcl->swfcl_vlan == NULL) {
    3224           0 :                 m_freem(m);
    3225           0 :                 return (NULL);
    3226             :         }
    3227             : 
    3228           0 :         if ((m->m_flags & M_VLANTAG)) {
    3229           0 :                 m->m_flags &= ~M_VLANTAG;
    3230           0 :                 return (m);
    3231             :         }
    3232             : 
    3233           0 :         if (m->m_len < sizeof(*evl) &&
    3234           0 :             (m = m_pullup(m, sizeof(*evl))) == NULL)
    3235           0 :                 return (NULL);
    3236           0 :         evl = mtod(m, struct ether_vlan_header *);
    3237             : 
    3238           0 :         if ((ntohs(evl->evl_encap_proto) != ETHERTYPE_VLAN) &&
    3239           0 :             (ntohs(evl->evl_encap_proto) != ETHERTYPE_QINQ)) {
    3240           0 :                 m_freem(m);
    3241           0 :                 return (NULL);
    3242             :         }
    3243             : 
    3244           0 :         m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&eh);
    3245           0 :         eh.ether_type = evl->evl_proto;
    3246             : 
    3247           0 :         m_adj(m, sizeof(*evl));
    3248           0 :         M_PREPEND(m, sizeof(eh), M_DONTWAIT);
    3249           0 :         if (m == NULL)
    3250           0 :                 return (NULL);
    3251           0 :         m_copyback(m, 0, sizeof(eh), &eh, M_NOWAIT);
    3252             : 
    3253             :         /*
    3254             :          * Update classify for vlan
    3255             :          */
    3256           0 :         if (m->m_len < sizeof(*evl) &&
    3257           0 :             (m = m_pullup(m, sizeof(*evl))) == NULL)
    3258           0 :                 return (NULL);
    3259           0 :         evl = mtod(m, struct ether_vlan_header *);
    3260             : 
    3261           0 :         if (ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN) {
    3262           0 :                 swfcl->swfcl_vlan->vlan_tpid = htons(ETHERTYPE_VLAN);
    3263           0 :                 swfcl->swfcl_vlan->vlan_vid =
    3264           0 :                     (evl->evl_tag & htons(EVL_VLID_MASK));
    3265           0 :                 swfcl->swfcl_vlan->vlan_pcp =
    3266           0 :                     EVL_PRIOFTAG(ntohs(evl->evl_tag));
    3267           0 :         } else {
    3268           0 :                 pool_put(&swfcl_pool, swfcl->swfcl_vlan);
    3269           0 :                 swfcl->swfcl_vlan = NULL;
    3270             :         }
    3271             : 
    3272           0 :         return (m);
    3273           0 : }
    3274             : 
    3275             : struct mbuf *
    3276           0 : swofp_action_push_vlan(struct switch_softc *sc, struct mbuf *m,
    3277             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    3278             : {
    3279           0 :         struct switch_flow_classify     *swfcl = swpld->swpld_swfcl;
    3280             :         struct ofp_action_push          *oap;
    3281             :         struct ether_header             *eh;
    3282           0 :         struct ether_vlan_header         evh;
    3283             : 
    3284             :         /*
    3285             :          * Expands 802.1Q VLAN header from M_VLANTAG because switch(4) doesn't
    3286             :          * use H/W tagging on port currently.
    3287             :          */
    3288           0 :         m = swofp_expand_8021q_tag(m);
    3289           0 :         if (m == NULL)
    3290           0 :                 return (NULL);
    3291             : 
    3292           0 :         oap = (struct ofp_action_push *)oah;
    3293             : 
    3294           0 :         if ((m->m_len < sizeof(*eh)) &&
    3295           0 :             ((m = m_pullup(m, sizeof(*eh))) == NULL)) {
    3296           0 :                 return (NULL);
    3297             :         }
    3298           0 :         eh = mtod(m, struct ether_header *);
    3299             : 
    3300           0 :         switch (ntohs(oap->ap_ethertype)) {
    3301             :         case ETHERTYPE_VLAN:
    3302           0 :                 if ((ntohs(eh->ether_type) == ETHERTYPE_VLAN) ||
    3303           0 :                     (ntohs(eh->ether_type) == ETHERTYPE_QINQ)) {
    3304           0 :                         m_freem(m);
    3305           0 :                         return (NULL);
    3306             :                 }
    3307             :                 break;
    3308             :         case ETHERTYPE_QINQ:
    3309           0 :                 if (ntohs(eh->ether_type) != ETHERTYPE_VLAN) {
    3310           0 :                         m_freem(m);
    3311           0 :                         return (NULL);
    3312             :                 }
    3313             :                 break;
    3314             :         default:
    3315           0 :                 m_freem(m);
    3316           0 :                 return (NULL);
    3317             :         }
    3318             : 
    3319           0 :         if (swfcl->swfcl_vlan == NULL) {
    3320           0 :                 swfcl->swfcl_vlan = pool_get(&swfcl_pool, PR_NOWAIT|PR_ZERO);
    3321           0 :                 if (swfcl->swfcl_vlan == NULL) {
    3322           0 :                         m_freem(m);
    3323           0 :                         return (NULL);
    3324             :                 }
    3325             :                 /* puts default vlan */
    3326           0 :                 swfcl->swfcl_vlan->vlan_vid = htons(1);
    3327           0 :         }
    3328             : 
    3329           0 :         m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
    3330           0 :         evh.evl_proto = evh.evl_encap_proto;
    3331           0 :         evh.evl_encap_proto = oap->ap_ethertype;
    3332           0 :         evh.evl_tag = (swfcl->swfcl_vlan->vlan_vid |
    3333           0 :             htons(swfcl->swfcl_vlan->vlan_pcp << EVL_PRIO_BITS));
    3334             : 
    3335           0 :         m_adj(m, ETHER_HDR_LEN);
    3336           0 :         M_PREPEND(m, sizeof(evh), M_DONTWAIT);
    3337           0 :         if (m == NULL)
    3338           0 :                 return (NULL);
    3339             : 
    3340           0 :         m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
    3341             : 
    3342             :         /*
    3343             :          * Update VLAN classification
    3344             :          */
    3345           0 :         swfcl->swfcl_vlan->vlan_tpid = oap->ap_ethertype;
    3346           0 :         swfcl->swfcl_vlan->vlan_vid = evh.evl_tag & htons(EVL_VLID_MASK);
    3347           0 :         swfcl->swfcl_vlan->vlan_pcp = EVL_PRIOFTAG(ntohs(evh.evl_tag));
    3348             : 
    3349           0 :         return (m);
    3350           0 : }
    3351             : 
    3352             : 
    3353             : /*
    3354             :  * OpenFlow protocol packet in
    3355             :  */
    3356             : int
    3357           0 : swofp_action_output_controller(struct switch_softc *sc, struct mbuf *m0,
    3358             :     struct swofp_pipeline_desc *swpld , uint16_t frame_max_len, uint8_t reason)
    3359             : {
    3360           0 :         struct swofp_ofs                *swofs = sc->sc_ofs;
    3361           0 :         struct switch_flow_classify     *swfcl = swpld->swpld_swfcl;
    3362             :         struct ofp_packet_in            *pin;
    3363             :         struct ofp_match                *om;
    3364             :         struct ofp_ox_match             *oxm;
    3365             :         struct mbuf                     *m;
    3366             :         caddr_t                          tail;
    3367             :         int                              match_len;
    3368             : 
    3369           0 :         if (reason != OFP_PKTIN_REASON_ACTION)
    3370           0 :                 frame_max_len = swofs->swofs_switch_config.cfg_miss_send_len;
    3371             :         /*
    3372             :          * ofp_match in packet_in has only OFP_XM_T_INPORT, OFP_MX_T_META,
    3373             :          * OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} and OFP_MX_T_TUNNEL_ID that
    3374             :          * if exist, so ofp_match length is determined here.
    3375             :          */
    3376             :         match_len = (
    3377             :             sizeof(*om) +                       /* struct ofp_match */
    3378             :             (sizeof(*oxm) + sizeof(uint32_t)) + /* OFP_MX_T_IMPORT */
    3379             :             (sizeof(*oxm) + sizeof(uint64_t))   /* OFP_MX_T_META */
    3380             :         );
    3381             : 
    3382           0 :         if (swfcl->swfcl_tunnel) {
    3383             :                 /* OFP_MX_T_TUNNEL_ID */
    3384             :                 match_len += (sizeof(*oxm) + sizeof(uint64_t));
    3385             : 
    3386             :                 /* OFP_XM_NXMT_TUNNEL_IPV{4|6}_{SRC|DST} */
    3387           0 :                 if (swfcl->swfcl_tunnel->tun_af == AF_INET)
    3388           0 :                         match_len += (sizeof(*oxm) + sizeof(uint32_t)) * 2;
    3389           0 :                 else if (swfcl->swfcl_tunnel->tun_af == AF_INET6)
    3390           0 :                         match_len += (sizeof(*oxm) +
    3391             :                             sizeof(struct in6_addr)) * 2;
    3392             :         }
    3393             : 
    3394           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    3395           0 :         if (m == NULL) {
    3396           0 :                 m_freem(m0);
    3397           0 :                 return (ENOBUFS);
    3398             :         }
    3399           0 :         if ((sizeof(*pin) + match_len) >= MHLEN) {
    3400           0 :                 MCLGET(m, M_DONTWAIT);
    3401           0 :                 if ((m->m_flags & M_EXT) == 0) {
    3402           0 :                         m_freem(m);
    3403           0 :                         m_freem(m0);
    3404           0 :                         return (ENOBUFS);
    3405             :                 }
    3406             :         }
    3407             : 
    3408           0 :         pin = mtod(m, struct ofp_packet_in *);
    3409           0 :         memset(pin, 0, sizeof(*pin));
    3410             : 
    3411           0 :         pin->pin_oh.oh_version = OFP_V_1_3;
    3412           0 :         pin->pin_oh.oh_type = OFP_T_PACKET_IN;
    3413           0 :         pin->pin_oh.oh_xid = htonl(swofs->swofs_xidnxt++);
    3414             : 
    3415           0 :         pin->pin_buffer_id = htonl(OFP_PKTOUT_NO_BUFFER);
    3416           0 :         pin->pin_table_id = swpld->swpld_table_id;
    3417           0 :         pin->pin_cookie = swpld->swpld_cookie;
    3418           0 :         pin->pin_reason = reason;
    3419             : 
    3420           0 :         if (frame_max_len) {
    3421             :                 /*
    3422             :                  * The switch should only truncate packets if it implements
    3423             :                  * buffering or the controller might end up sending PACKET_OUT
    3424             :                  * responses with truncated packets that will eventually end
    3425             :                  * up on the network.
    3426             :                  */
    3427           0 :                 if (frame_max_len < m0->m_pkthdr.len) {
    3428           0 :                         m_freem(m);
    3429           0 :                         m_freem(m0);
    3430           0 :                         return (EMSGSIZE);
    3431             :                 }
    3432           0 :                 pin->pin_total_len = htons(m0->m_pkthdr.len);
    3433           0 :         }
    3434             : 
    3435             :         /*
    3436             :          * It's ensured continuous memory space between ofp_mach space
    3437             :          */
    3438           0 :         om = &pin->pin_match;
    3439           0 :         swofp_ox_match_put_start(om);
    3440           0 :         swofp_ox_match_put_uint32(om, OFP_XM_T_IN_PORT, swfcl->swfcl_in_port);
    3441           0 :         swofp_ox_match_put_uint64(om, OFP_XM_T_META, swpld->swpld_metadata);
    3442           0 :         if (swfcl->swfcl_tunnel) {
    3443           0 :                 swofp_ox_match_put_uint64(om, OFP_XM_T_TUNNEL_ID,
    3444           0 :                     be64toh(swfcl->swfcl_tunnel->tun_key));
    3445             : 
    3446           0 :                 if (swfcl->swfcl_tunnel->tun_af == AF_INET) {
    3447           0 :                         swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_SRC,
    3448             :                             sizeof(uint32_t),
    3449           0 :                             (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_src);
    3450           0 :                         swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV4_DST,
    3451             :                             sizeof(uint32_t),
    3452           0 :                             (caddr_t)&swfcl->swfcl_tunnel->tun_ipv4_dst);
    3453           0 :                 } else if (swfcl->swfcl_tunnel->tun_af == AF_INET6) {
    3454           0 :                         swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_SRC,
    3455             :                             sizeof(struct in6_addr),
    3456           0 :                             (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_src);
    3457           0 :                         swofp_nx_match_put(om, OFP_XM_NXMT_TUNNEL_IPV6_DST,
    3458             :                             sizeof(struct in6_addr),
    3459           0 :                             (caddr_t)&swfcl->swfcl_tunnel->tun_ipv6_dst);
    3460           0 :                 }
    3461             :         }
    3462           0 :         match_len = swofp_ox_match_put_end(om); /* match_len include padding */
    3463             : 
    3464             :         /*
    3465             :          * Adjust alignment for Ethernet header
    3466             :          */
    3467           0 :         tail = (caddr_t)pin +
    3468           0 :             offsetof(struct ofp_packet_in, pin_match) + match_len;
    3469           0 :         memset(tail, 0, ETHER_ALIGN);
    3470             : 
    3471           0 :         m->m_len = m->m_pkthdr.len =
    3472           0 :             offsetof(struct ofp_packet_in, pin_match) + match_len + ETHER_ALIGN;
    3473             : 
    3474           0 :         pin->pin_oh.oh_length =
    3475           0 :             htons(m->m_pkthdr.len + ntohs(pin->pin_total_len));
    3476             : 
    3477           0 :         if (frame_max_len) {
    3478             :                 /* m_cat() doesn't update the m_pkthdr.len */
    3479           0 :                 m_cat(m, m0);
    3480           0 :                 m->m_pkthdr.len += ntohs(pin->pin_total_len);
    3481           0 :         }
    3482             : 
    3483           0 :         (void)swofp_output(sc, m);
    3484             : 
    3485           0 :         return (0);
    3486           0 : }
    3487             : 
    3488             : struct mbuf *
    3489           0 : swofp_action_output(struct switch_softc *sc, struct mbuf *m,
    3490             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    3491             : {
    3492             :         struct ofp_action_output        *oao;
    3493             :         struct switch_port              *swpo;
    3494             :         struct mbuf                     *mc;
    3495             : 
    3496           0 :         m->m_pkthdr.csum_flags = 0;
    3497             : 
    3498           0 :         if ((m = swofp_apply_set_field(m, swpld)) == NULL)
    3499           0 :                 return (NULL);
    3500             : 
    3501           0 :         oao = (struct ofp_action_output *)oah;
    3502             : 
    3503           0 :         switch (ntohl(oao->ao_port)) {
    3504             :         case OFP_PORT_CONTROLLER:
    3505             :         case OFP_PORT_FLOWTABLE:
    3506           0 :                 if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) {
    3507           0 :                         m_freem(m);
    3508           0 :                         return (NULL);
    3509             :                 }
    3510             :         }
    3511             : 
    3512           0 :         switch (ntohl(oao->ao_port)) {
    3513             :         case OFP_PORT_CONTROLLER:
    3514           0 :                 swofp_action_output_controller(sc, mc, swpld,
    3515           0 :                     ntohs(oao->ao_max_len), swpld->swpld_tablemiss ?
    3516             :                     OFP_PKTIN_REASON_NO_MATCH : OFP_PKTIN_REASON_ACTION);
    3517           0 :                 break;
    3518             :         case OFP_PORT_FLOWTABLE:
    3519           0 :                 swofp_forward_ofs(sc, swpld->swpld_swfcl, mc);
    3520           0 :                 break;
    3521             :         case OFP_PORT_FLOOD:
    3522           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    3523           0 :                         if (swpo->swpo_port_no !=
    3524           0 :                             swpld->swpld_swfcl->swfcl_in_port)
    3525           0 :                                 TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
    3526             :                                     swpo_fwdp_next);
    3527             :                 }
    3528             :                 break;
    3529             :         case OFP_PORT_INPUT:
    3530           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    3531           0 :                         if (swpo->swpo_port_no ==
    3532           0 :                             swpld->swpld_swfcl->swfcl_in_port) {
    3533           0 :                                 TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
    3534             :                                     swpo_fwdp_next);
    3535           0 :                                 break;
    3536             :                         }
    3537             :                 }
    3538             :                 break;
    3539             :         case OFP_PORT_NORMAL:
    3540             :         case OFP_PORT_ALL:
    3541             :         case OFP_PORT_ANY:
    3542             :                 /* no support yet */
    3543             :                 break;
    3544             :         case OFP_PORT_LOCAL:
    3545           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    3546           0 :                         if (swpo->swpo_flags & IFBIF_LOCAL) {
    3547           0 :                                 TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
    3548             :                                     swpo_fwdp_next);
    3549           0 :                                 break;
    3550             :                         }
    3551             :                 }
    3552             :                 break;
    3553             :         default:
    3554           0 :                 TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    3555           0 :                         if (swpo->swpo_port_no == ntohl(oao->ao_port))
    3556           0 :                                 TAILQ_INSERT_HEAD(&swpld->swpld_fwdp_q, swpo,
    3557             :                                     swpo_fwdp_next);
    3558             :                 }
    3559             :                 break;
    3560             :         }
    3561             : 
    3562           0 :         if (!TAILQ_EMPTY(&swpld->swpld_fwdp_q)) {
    3563           0 :                 if ((mc = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT)) == NULL) {
    3564           0 :                         m_freem(m);
    3565           0 :                         return (NULL);
    3566             :                 }
    3567           0 :                 switch_port_egress(sc, &swpld->swpld_fwdp_q, mc);
    3568           0 :                 TAILQ_INIT(&swpld->swpld_fwdp_q);
    3569           0 :         }
    3570             : 
    3571           0 :         return (m);
    3572           0 : }
    3573             : 
    3574             : 
    3575             : struct mbuf *
    3576           0 : swofp_action_group_all(struct switch_softc *sc, struct mbuf *m,
    3577             :     struct swofp_pipeline_desc *swpld, struct swofp_group_entry *swge)
    3578             : {
    3579             :         struct ofp_bucket               *bucket;
    3580             :         struct ofp_action_header        *ah;
    3581             :         int                              actions_len;
    3582             :         struct swofp_pipeline_desc      *clean_swpld = NULL;
    3583           0 :         struct switch_flow_classify      swfcl;
    3584             :         struct mbuf                     *n;
    3585             : 
    3586             :         /* Don't do anything if we don't have buckets. */
    3587           0 :         if (swge->swge_buckets == NULL)
    3588           0 :                 return (m);
    3589             : 
    3590           0 :         OFP_BUCKETS_FOREACH(swge->swge_buckets,
    3591             :             swge->swge_buckets_len, bucket) {
    3592           0 :                 if (switch_swfcl_dup(swpld->swpld_swfcl, &swfcl) != 0)
    3593             :                         goto failed;
    3594             : 
    3595           0 :                 clean_swpld = swofp_pipeline_desc_create(&swfcl);
    3596           0 :                 if (clean_swpld == NULL)
    3597             :                         goto failed;
    3598             : 
    3599           0 :                 if ((n = m_dup_pkt(m,  ETHER_ALIGN, M_NOWAIT)) == NULL)
    3600             :                         goto failed;
    3601             : 
    3602           0 :                 actions_len = (ntohs(bucket->b_len) -
    3603             :                     (offsetof(struct ofp_bucket, b_actions)));
    3604             : 
    3605           0 :                 OFP_ACTION_FOREACH(bucket->b_actions, actions_len, ah) {
    3606           0 :                         n = swofp_execute_action(sc, n, clean_swpld, ah);
    3607           0 :                         if (n == NULL)
    3608             :                                 goto failed;
    3609             :                 }
    3610             : 
    3611           0 :                 m_freem(n);
    3612           0 :                 swofp_pipeline_desc_destroy(clean_swpld);
    3613             :                 clean_swpld = NULL;
    3614           0 :                 switch_swfcl_free(&swfcl);
    3615             :         }
    3616             : 
    3617           0 :         return (m);
    3618             : 
    3619             :  failed:
    3620           0 :         m_freem(m);
    3621           0 :         if (clean_swpld)
    3622           0 :                 swofp_pipeline_desc_destroy(clean_swpld);
    3623           0 :         return (NULL);
    3624           0 : }
    3625             : 
    3626             : struct mbuf *
    3627           0 : swofp_action_group(struct switch_softc *sc, struct mbuf *m,
    3628             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    3629             : {
    3630             :         struct ofp_action_group         *oag;
    3631             :         struct swofp_group_entry        *swge;
    3632             : 
    3633           0 :         oag = (struct ofp_action_group *)oah;
    3634             : 
    3635           0 :         swge = swofp_group_entry_lookup(sc, ntohl(oag->ag_group_id));
    3636           0 :         if (swge == NULL) {
    3637           0 :                 m_freem(m);
    3638           0 :                 return (NULL);
    3639             :         }
    3640             : 
    3641           0 :         swge->swge_packet_count++;
    3642           0 :         swge->swge_byte_count += m->m_pkthdr.len;
    3643             : 
    3644           0 :         switch (swge->swge_type) {
    3645             :         case OFP_GROUP_T_ALL:
    3646           0 :                 return swofp_action_group_all(sc, m, swpld, swge);
    3647             :         case OFP_GROUP_T_INDIRECT:
    3648             :         case OFP_GROUP_T_FAST_FAILOVER:
    3649             :         case OFP_GROUP_T_SELECT:
    3650           0 :                 m_freem(m);
    3651           0 :                 return (NULL);
    3652             :         }
    3653             : 
    3654           0 :         return (m);
    3655           0 : }
    3656             : 
    3657             : struct mbuf *
    3658           0 : swofp_apply_set_field_udp(struct mbuf *m, int off,
    3659             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3660             : {
    3661             :         struct udphdr *uh;
    3662             : 
    3663           0 :         if (m->m_len < (off + sizeof(*uh)) &&
    3664           0 :             (m = m_pullup(m, off + sizeof(*uh))) == NULL)
    3665           0 :                 return NULL;
    3666             : 
    3667           0 :         uh = (struct udphdr *)((m)->m_data + off);
    3668             : 
    3669           0 :         if (pre_swfcl->swfcl_udp) {
    3670           0 :                 uh->uh_sport = pre_swfcl->swfcl_udp->udp_src;
    3671           0 :                 uh->uh_dport = pre_swfcl->swfcl_udp->udp_dst;
    3672           0 :                 memcpy(swfcl->swfcl_udp, pre_swfcl->swfcl_udp,
    3673             :                     sizeof(*swfcl->swfcl_udp));
    3674           0 :         }
    3675             : 
    3676           0 :         return (m);
    3677           0 : }
    3678             : 
    3679             : struct mbuf *
    3680           0 : swofp_apply_set_field_tcp(struct mbuf *m, int off,
    3681             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3682             : {
    3683             :         struct tcphdr *th;
    3684             : 
    3685           0 :         if (m->m_len < (off + sizeof(*th)) &&
    3686           0 :             (m = m_pullup(m, off + sizeof(*th))) == NULL)
    3687           0 :                 return NULL;
    3688             : 
    3689           0 :         th = (struct tcphdr *)((m)->m_data + off);
    3690             : 
    3691           0 :         if (pre_swfcl->swfcl_tcp) {
    3692           0 :                 th->th_sport = pre_swfcl->swfcl_tcp->tcp_src;
    3693           0 :                 th->th_dport = pre_swfcl->swfcl_tcp->tcp_dst;
    3694             : 
    3695           0 :                 memcpy(swfcl->swfcl_tcp, pre_swfcl->swfcl_tcp,
    3696             :                     sizeof(*swfcl->swfcl_tcp));
    3697           0 :         }
    3698             : 
    3699           0 :         return (m);
    3700           0 : }
    3701             : 
    3702             : #ifdef INET6
    3703             : struct mbuf *
    3704           0 : swofp_apply_set_field_nd6(struct mbuf *m, int off,
    3705             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3706             : {
    3707             :         struct icmp6_hdr                *icmp6;
    3708             :         struct nd_neighbor_advert       *nd_na;
    3709             :         struct nd_neighbor_solicit      *nd_ns;
    3710           0 :         union nd_opts                    ndopts;
    3711           0 :         int                              icmp6len = m->m_pkthdr.len - off;
    3712             :         int                              lladdrlen;
    3713             :         uint8_t                         *lladdr;
    3714             : 
    3715           0 :         if (pre_swfcl->swfcl_nd6 == NULL)
    3716           0 :                 return (m);
    3717             : 
    3718           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
    3719           0 :         if (icmp6 == NULL)
    3720             :                 goto failed;
    3721             : 
    3722           0 :         switch (icmp6->icmp6_type) {
    3723             :         case ND_NEIGHBOR_ADVERT:
    3724           0 :                 if (icmp6len < sizeof(struct nd_neighbor_advert))
    3725             :                         goto failed;
    3726             :                 break;
    3727             :         case ND_NEIGHBOR_SOLICIT:
    3728           0 :                 if (icmp6len < sizeof(struct nd_neighbor_solicit))
    3729             :                         goto failed;
    3730             :                 break;
    3731             :         }
    3732             : 
    3733           0 :         switch (icmp6->icmp6_type) {
    3734             :         case ND_NEIGHBOR_ADVERT:
    3735           0 :                 IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m,
    3736             :                     off, icmp6len);
    3737           0 :                 if (nd_na == NULL)
    3738             :                         goto failed;
    3739             : 
    3740           0 :                 nd_na->nd_na_target = pre_swfcl->swfcl_nd6->nd6_target;
    3741           0 :                 icmp6len -= sizeof(*nd_na);
    3742           0 :                 nd6_option_init(nd_na + 1, icmp6len, &ndopts);
    3743           0 :                 if (nd6_options(&ndopts) < 0)
    3744             :                         goto failed;
    3745             : 
    3746           0 :                 if (!ndopts.nd_opts_tgt_lladdr)
    3747             :                         goto failed;
    3748             : 
    3749           0 :                 lladdr = (char *)(ndopts.nd_opts_tgt_lladdr + 1);
    3750           0 :                 lladdrlen = (ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3) - 2;
    3751             : 
    3752             :                 /* switch(4) only supports Ethernet interfaces */
    3753           0 :                 if (lladdrlen != ETHER_ADDR_LEN)
    3754             :                         goto failed;
    3755             : 
    3756           0 :                 memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr,
    3757             :                     ETHER_ADDR_LEN);
    3758           0 :                 break;
    3759             :         case ND_NEIGHBOR_SOLICIT:
    3760           0 :                 IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m,
    3761             :                     off, icmp6len);
    3762           0 :                 if (nd_ns == NULL)
    3763             :                         goto failed;
    3764             : 
    3765           0 :                 nd_ns->nd_ns_target = pre_swfcl->swfcl_nd6->nd6_target;
    3766           0 :                 icmp6len -= sizeof(*nd_ns);
    3767             : 
    3768           0 :                 nd6_option_init(nd_ns + 1, icmp6len, &ndopts);
    3769           0 :                 if (nd6_options(&ndopts) < 0)
    3770             :                         goto failed;
    3771             : 
    3772           0 :                 if (!ndopts.nd_opts_src_lladdr)
    3773             :                         goto failed;
    3774             : 
    3775           0 :                 lladdr = (char *)(ndopts.nd_opts_src_lladdr + 1);
    3776           0 :                 lladdrlen = (ndopts.nd_opts_src_lladdr->nd_opt_len << 3) - 2;
    3777             : 
    3778             :                 /* switch(4) only supports Ethernet interfaces */
    3779           0 :                 if (lladdrlen != ETHER_ADDR_LEN)
    3780             :                         goto failed;
    3781           0 :                 memcpy(lladdr, pre_swfcl->swfcl_nd6->nd6_lladdr,
    3782             :                     ETHER_ADDR_LEN);
    3783           0 :                 break;
    3784             :         }
    3785             : 
    3786           0 :         memcpy(swfcl->swfcl_nd6, pre_swfcl->swfcl_nd6,
    3787             :             sizeof(*swfcl->swfcl_nd6));
    3788             : 
    3789           0 :         return (m);
    3790             : 
    3791             :  failed:
    3792           0 :         m_freem(m);
    3793           0 :         return (NULL);
    3794           0 : }
    3795             : 
    3796             : struct mbuf *
    3797           0 : swofp_apply_set_field_icmpv6(struct mbuf *m, int off,
    3798             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3799             : {
    3800             :         struct icmp6_hdr        *icmp6;
    3801             : 
    3802           0 :         IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
    3803           0 :         if (icmp6 == NULL)
    3804           0 :                 return (NULL); /* m was already freed */
    3805             : 
    3806           0 :         if (pre_swfcl->swfcl_icmpv6) {
    3807           0 :                 icmp6->icmp6_type = pre_swfcl->swfcl_icmpv6->icmpv6_type;
    3808           0 :                 icmp6->icmp6_code = pre_swfcl->swfcl_icmpv6->icmpv6_code;
    3809             : 
    3810           0 :                 memcpy(swfcl->swfcl_icmpv6, pre_swfcl->swfcl_icmpv6,
    3811             :                     sizeof(*swfcl->swfcl_icmpv6));
    3812           0 :         }
    3813             : 
    3814           0 :         m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
    3815             : 
    3816           0 :         switch (icmp6->icmp6_type) {
    3817             :         case ND_NEIGHBOR_ADVERT:
    3818             :         case ND_NEIGHBOR_SOLICIT:
    3819           0 :                 return swofp_apply_set_field_nd6(m, off, pre_swfcl, swfcl);
    3820             :         }
    3821             : 
    3822           0 :         return (m);
    3823           0 : }
    3824             : #endif /* INET6 */
    3825             : 
    3826             : struct mbuf *
    3827           0 : swofp_apply_set_field_icmpv4(struct mbuf *m, int off,
    3828             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3829             : {
    3830             :         struct icmp *icmp;
    3831             : 
    3832           0 :         if (m->m_len < (off + ICMP_MINLEN) &&
    3833           0 :             (m = m_pullup(m, (off + ICMP_MINLEN))) == NULL)
    3834           0 :                 return NULL;
    3835             : 
    3836           0 :         icmp = (struct icmp *)((m)->m_data + off);
    3837             : 
    3838           0 :         if (pre_swfcl->swfcl_icmpv4) {
    3839           0 :                 icmp->icmp_type = pre_swfcl->swfcl_icmpv4->icmpv4_type;
    3840           0 :                 icmp->icmp_code = pre_swfcl->swfcl_icmpv4->icmpv4_code;
    3841             : 
    3842           0 :                 memcpy(swfcl->swfcl_icmpv4, pre_swfcl->swfcl_icmpv4,
    3843             :                     sizeof(*swfcl->swfcl_icmpv4));
    3844           0 :         }
    3845             : 
    3846           0 :         m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
    3847             : 
    3848           0 :         return (m);
    3849           0 : }
    3850             : 
    3851             : #ifdef INET6
    3852             : struct mbuf *
    3853           0 : swofp_apply_set_field_ipv6(struct mbuf *m, int off,
    3854             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3855             : {
    3856             :         struct ip6_hdr  *ip6;
    3857             :         int              hlen;
    3858             :         /* max size is 802.1ad header size */
    3859           0 :         u_char           eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN];
    3860             : 
    3861           0 :         if (m->m_len < (off + sizeof(*ip6)) &&
    3862           0 :             (m = m_pullup(m, off + sizeof(*ip6))) == NULL)
    3863           0 :                 return (NULL);
    3864             : 
    3865           0 :         ip6 = (struct ip6_hdr *)(mtod(m, caddr_t) + off);
    3866             : 
    3867           0 :         if (pre_swfcl->swfcl_ipv6) {
    3868             :                 /* set version, class and flow label at once */
    3869           0 :                 ip6->ip6_flow =  (IPV6_VERSION |
    3870           0 :                     (pre_swfcl->swfcl_ipv6->ipv6_flow_label &
    3871           0 :                     IPV6_FLOWLABEL_MASK) |
    3872           0 :                     htonl(pre_swfcl->swfcl_ipv6->ipv6_tclass << 20));
    3873           0 :                 ip6->ip6_hlim = pre_swfcl->swfcl_ipv6->ipv6_hlimit;
    3874           0 :                 ip6->ip6_nxt = pre_swfcl->swfcl_ipv6->ipv6_nxt;
    3875             : 
    3876           0 :                 ip6->ip6_src = pre_swfcl->swfcl_ipv6->ipv6_src;
    3877           0 :                 ip6->ip6_dst = pre_swfcl->swfcl_ipv6->ipv6_dst;
    3878             : 
    3879           0 :                 memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
    3880             :                     sizeof(*pre_swfcl->swfcl_ipv6));
    3881           0 :         }
    3882             : 
    3883             :         hlen = sizeof(*ip6);
    3884             : 
    3885           0 :         switch (swfcl->swfcl_ipv6->ipv6_nxt) {
    3886             :         case IPPROTO_UDP:
    3887           0 :                 m = swofp_apply_set_field_udp(m, (off + hlen),
    3888             :                     pre_swfcl, swfcl);
    3889           0 :                 if (m == NULL)
    3890           0 :                         return (NULL);
    3891           0 :                 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
    3892           0 :                 break;
    3893             :         case IPPROTO_TCP:
    3894           0 :                 m =  swofp_apply_set_field_tcp(m, (off + hlen),
    3895             :                     pre_swfcl, swfcl);
    3896           0 :                 if (m == NULL)
    3897           0 :                         return (NULL);
    3898           0 :                 m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
    3899           0 :                 break;
    3900             :         case IPPROTO_ICMPV6:
    3901           0 :                 m =  swofp_apply_set_field_icmpv6(m, (off + hlen),
    3902             :                     pre_swfcl, swfcl);
    3903           0 :                 if (m == NULL)
    3904           0 :                         return (NULL);
    3905             :                 break;
    3906             :         }
    3907             : 
    3908             :         /*
    3909             :          * Recalculate checksums:
    3910             :          * It doesn't use H/W offload because doesn't know to send a frame
    3911             :          * from which interface.
    3912             :          */
    3913           0 :         m_copydata(m, 0, off, eh_bk);
    3914           0 :         m_adj(m, off);
    3915             : 
    3916           0 :         if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
    3917           0 :                 return (NULL);
    3918             : 
    3919           0 :         in6_proto_cksum_out(m, NULL);
    3920             : 
    3921           0 :         M_PREPEND(m, off, M_DONTWAIT);
    3922           0 :         if (m == NULL)
    3923           0 :                 return (NULL);
    3924             : 
    3925           0 :         m_copyback(m, 0, off, eh_bk, M_DONTWAIT);
    3926             : 
    3927           0 :         return (m);
    3928           0 : }
    3929             : #endif /* INET6 */
    3930             : 
    3931             : struct mbuf *
    3932           0 : swofp_apply_set_field_ipv4(struct mbuf *m, int off,
    3933             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    3934             : {
    3935             :         struct ip       *ip;
    3936             :         int              hlen;
    3937             :         /* max size is 802.1ad header size */
    3938           0 :         u_char           eh_bk[sizeof(struct ether_vlan_header) + EVL_ENCAPLEN];
    3939             : 
    3940           0 :         if (m->m_len < (off + sizeof(*ip)) &&
    3941           0 :             (m = m_pullup(m, off + sizeof(*ip))) == NULL)
    3942           0 :                 return (NULL);
    3943             : 
    3944           0 :         ip = (struct ip *)(mtod(m, caddr_t) + off);
    3945             : 
    3946           0 :         if (pre_swfcl->swfcl_ipv4) {
    3947           0 :                 ip->ip_p = pre_swfcl->swfcl_ipv4->ipv4_proto;
    3948           0 :                 ip->ip_tos = pre_swfcl->swfcl_ipv4->ipv4_tos;
    3949             : 
    3950           0 :                 memcpy(&ip->ip_src.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_src,
    3951             :                     sizeof(uint32_t));
    3952           0 :                 memcpy(&ip->ip_dst.s_addr, &pre_swfcl->swfcl_ipv4->ipv4_dst,
    3953             :                     sizeof(uint32_t));
    3954             : 
    3955           0 :                 memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
    3956             :                     sizeof(*pre_swfcl->swfcl_ipv4));
    3957           0 :         }
    3958             : 
    3959           0 :         hlen = (ip->ip_hl << 2);
    3960             : 
    3961           0 :         switch (swfcl->swfcl_ipv4->ipv4_proto) {
    3962             :         case IPPROTO_UDP:
    3963           0 :                 m = swofp_apply_set_field_udp(m, (off + hlen),
    3964             :                     pre_swfcl, swfcl);
    3965           0 :                 if (m == NULL)
    3966           0 :                         return (NULL);
    3967           0 :                 m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
    3968           0 :                 break;
    3969             :         case IPPROTO_TCP:
    3970           0 :                 m =  swofp_apply_set_field_tcp(m, (off + hlen),
    3971             :                     pre_swfcl, swfcl);
    3972           0 :                 if (m == NULL)
    3973           0 :                         return (NULL);
    3974           0 :                 m->m_pkthdr.csum_flags |= M_TCP_CSUM_OUT;
    3975           0 :                 break;
    3976             :         case IPPROTO_ICMP:
    3977           0 :                 m =  swofp_apply_set_field_icmpv4(m, (off + hlen),
    3978             :                     pre_swfcl, swfcl);
    3979           0 :                 if (m == NULL)
    3980           0 :                         return (NULL);
    3981             :                 break;
    3982             :         }
    3983             : 
    3984             :         /*
    3985             :          * Recalculate checksums:
    3986             :          * It doesn't use H/W offload because doesn't know to send a frame
    3987             :          * from which interface.
    3988             :          */
    3989           0 :         m_copydata(m, 0, off, eh_bk);
    3990           0 :         m_adj(m, off);
    3991             : 
    3992           0 :         if (m->m_len < hlen && ((m = m_pullup(m, hlen)) == NULL))
    3993           0 :                 return (NULL);
    3994           0 :         ip = mtod(m, struct ip *);
    3995             : 
    3996           0 :         ip->ip_sum = 0;
    3997           0 :         in_proto_cksum_out(m, NULL);
    3998           0 :         ip->ip_sum = in_cksum(m, hlen);
    3999             : 
    4000           0 :         M_PREPEND(m, off, M_DONTWAIT);
    4001           0 :         if (m == NULL)
    4002           0 :                 return (NULL);
    4003             : 
    4004           0 :         m_copyback(m, 0, off, eh_bk, M_DONTWAIT);
    4005             : 
    4006           0 :         return (m);
    4007           0 : }
    4008             : 
    4009             : struct mbuf *
    4010           0 : swofp_apply_set_field_arp( struct mbuf *m, int off,
    4011             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    4012             : {
    4013             :         struct ether_arp *ea;
    4014             : 
    4015           0 :         if (m->m_len < (off + sizeof(*ea)) &&
    4016           0 :             (m = m_pullup(m, off + sizeof(*ea))) == NULL)
    4017           0 :                 return (NULL);
    4018             : 
    4019           0 :         ea = (struct ether_arp *)((m)->m_data + off);
    4020             : 
    4021           0 :         if (pre_swfcl->swfcl_arp) {
    4022           0 :                 ea->arp_op = pre_swfcl->swfcl_arp->_arp_op;
    4023             : 
    4024           0 :                 memcpy(&ea->arp_sha, pre_swfcl->swfcl_arp->arp_sha,
    4025             :                     ETHER_ADDR_LEN);
    4026           0 :                 memcpy(&ea->arp_tha, pre_swfcl->swfcl_arp->arp_tha,
    4027             :                     ETHER_ADDR_LEN);
    4028           0 :                 memcpy(&ea->arp_spa, &pre_swfcl->swfcl_arp->arp_sip,
    4029             :                     sizeof(uint32_t));
    4030           0 :                 memcpy(&ea->arp_tpa, &pre_swfcl->swfcl_arp->arp_tip,
    4031             :                     sizeof(uint32_t));
    4032           0 :                 memcpy(swfcl->swfcl_arp, pre_swfcl->swfcl_arp,
    4033             :                     sizeof(*swfcl->swfcl_arp));
    4034           0 :         }
    4035             : 
    4036           0 :         return (m);
    4037           0 : }
    4038             : 
    4039             : struct mbuf *
    4040           0 : swofp_apply_set_field_ether(struct mbuf *m, int off,
    4041             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    4042             : {
    4043             :         struct ether_header             *eh;
    4044             :         struct ether_vlan_header        *evl = NULL;
    4045             :         uint16_t                        *ether_type;
    4046             : 
    4047           0 :         m = swofp_expand_8021q_tag(m);
    4048           0 :         if (m == NULL)
    4049           0 :                 return (NULL);
    4050             : 
    4051             :         /*
    4052             :          * pullup to maximum size QinQ header
    4053             :          */
    4054           0 :         if ((m = m_pullup(m, (sizeof(*evl) + EVL_ENCAPLEN))) == NULL)
    4055           0 :                 return (NULL);
    4056             : 
    4057           0 :         eh = mtod(m, struct ether_header *);
    4058             : 
    4059           0 :         switch (ntohs(eh->ether_type)) {
    4060             :         case ETHERTYPE_QINQ:
    4061             :                 off = EVL_ENCAPLEN + sizeof(struct ether_vlan_header);
    4062           0 :                 evl = mtod(m, struct ether_vlan_header *);
    4063           0 :                 ether_type = (uint16_t *)(mtod(m, caddr_t) + EVL_ENCAPLEN +
    4064             :                     offsetof(struct ether_vlan_header, evl_proto));
    4065           0 :                 break;
    4066             :         case ETHERTYPE_VLAN:
    4067             :                 off = sizeof(struct ether_vlan_header);
    4068           0 :                 evl = mtod(m, struct ether_vlan_header *);
    4069           0 :                 ether_type = &evl->evl_proto;
    4070           0 :                 break;
    4071             :         default:
    4072             :                 off = sizeof(struct ether_header);
    4073             :                 ether_type = &eh->ether_type;
    4074           0 :                 break;
    4075             :         }
    4076             : 
    4077           0 :         if (pre_swfcl->swfcl_vlan) {
    4078           0 :                 switch (ntohs(eh->ether_type)) {
    4079             :                 case ETHERTYPE_QINQ:
    4080             :                 case ETHERTYPE_VLAN:
    4081           0 :                         evl->evl_tag = (pre_swfcl->swfcl_vlan->vlan_vid |
    4082           0 :                             htons(pre_swfcl->swfcl_vlan->vlan_pcp <<
    4083             :                             EVL_PRIO_BITS));
    4084           0 :                         break;
    4085             :                 default:
    4086             :                         break;
    4087             :                 }
    4088             : 
    4089             :                 /* Update the classifier if it exists. */
    4090           0 :                 if (swfcl->swfcl_vlan)
    4091           0 :                         memcpy(swfcl->swfcl_vlan, pre_swfcl->swfcl_vlan,
    4092             :                             sizeof(*swfcl->swfcl_vlan));
    4093             :         }
    4094             : 
    4095           0 :         if (pre_swfcl->swfcl_ether) {
    4096           0 :                 memcpy(eh->ether_shost, pre_swfcl->swfcl_ether->eth_src,
    4097             :                     ETHER_ADDR_LEN);
    4098           0 :                 memcpy(eh->ether_dhost, pre_swfcl->swfcl_ether->eth_dst,
    4099             :                     ETHER_ADDR_LEN);
    4100           0 :                 *ether_type = pre_swfcl->swfcl_ether->eth_type;
    4101           0 :                 memcpy(swfcl->swfcl_ether, pre_swfcl->swfcl_ether,
    4102             :                     sizeof(*swfcl->swfcl_ether));
    4103           0 :         }
    4104             : 
    4105           0 :         switch (ntohs(*ether_type)) {
    4106             :         case ETHERTYPE_ARP:
    4107           0 :                 return swofp_apply_set_field_arp(m, off, pre_swfcl, swfcl);
    4108             :         case ETHERTYPE_IP:
    4109           0 :                 return swofp_apply_set_field_ipv4(m, off, pre_swfcl, swfcl);
    4110             : #ifdef INET6
    4111             :         case ETHERTYPE_IPV6:
    4112           0 :                 return swofp_apply_set_field_ipv6(m, off, pre_swfcl, swfcl);
    4113             : #endif /* INET6 */
    4114             :         case ETHERTYPE_MPLS:
    4115             :                 /* unsupported yet */
    4116             :                 break;
    4117             :         }
    4118             : 
    4119           0 :         return (m);
    4120           0 : }
    4121             : 
    4122             : struct mbuf *
    4123           0 : swofp_apply_set_field_tunnel(struct mbuf *m, int off,
    4124             :     struct switch_flow_classify *pre_swfcl, struct switch_flow_classify *swfcl)
    4125             : {
    4126             :         struct bridge_tunneltag *brtag;
    4127             : 
    4128           0 :         if (pre_swfcl->swfcl_tunnel) {
    4129           0 :                 if ((brtag = bridge_tunneltag(m)) == NULL) {
    4130           0 :                         m_freem(m);
    4131           0 :                         return (NULL);
    4132             :                 }
    4133             : 
    4134           0 :                 brtag->brtag_id = be64toh(pre_swfcl->swfcl_tunnel->tun_key);
    4135             : 
    4136           0 :                 if (pre_swfcl->swfcl_tunnel->tun_ipv4_dst.s_addr !=
    4137             :                     INADDR_ANY) {
    4138           0 :                         brtag->brtag_peer.sin.sin_family =
    4139           0 :                             brtag->brtag_local.sin.sin_family = AF_INET;
    4140           0 :                         brtag->brtag_local.sin.sin_addr =
    4141           0 :                             pre_swfcl->swfcl_tunnel->tun_ipv4_src;
    4142           0 :                         brtag->brtag_peer.sin.sin_addr =
    4143           0 :                             pre_swfcl->swfcl_tunnel->tun_ipv4_dst;
    4144           0 :                 } else if (!IN6_IS_ADDR_UNSPECIFIED(
    4145             :                     &pre_swfcl->swfcl_tunnel->tun_ipv6_dst)) {
    4146           0 :                         brtag->brtag_peer.sin6.sin6_family =
    4147           0 :                             brtag->brtag_local.sin.sin_family = AF_INET6;
    4148           0 :                         brtag->brtag_local.sin6.sin6_addr =
    4149           0 :                             pre_swfcl->swfcl_tunnel->tun_ipv6_src;
    4150           0 :                         brtag->brtag_peer.sin6.sin6_addr =
    4151           0 :                             pre_swfcl->swfcl_tunnel->tun_ipv6_dst;
    4152             :                 } else {
    4153           0 :                         bridge_tunneluntag(m);
    4154           0 :                         m_freem(m);
    4155           0 :                         return (NULL);
    4156             :                 }
    4157             : 
    4158             :                 /*
    4159             :                  * It can't be used by apply-action instruction.
    4160             :                  */
    4161           0 :                 if (swfcl->swfcl_tunnel) {
    4162           0 :                         memcpy(swfcl->swfcl_tunnel, pre_swfcl->swfcl_tunnel,
    4163             :                             sizeof(*pre_swfcl->swfcl_tunnel));
    4164           0 :                 }
    4165             :         }
    4166             : 
    4167           0 :         return swofp_apply_set_field_ether(m, 0, pre_swfcl, swfcl);
    4168           0 : }
    4169             : 
    4170             : struct mbuf *
    4171           0 : swofp_apply_set_field(struct mbuf *m, struct swofp_pipeline_desc *swpld)
    4172             : {
    4173           0 :         return swofp_apply_set_field_tunnel(m, 0,
    4174           0 :             &swpld->swpld_pre_swfcl, swpld->swpld_swfcl);
    4175             : }
    4176             : 
    4177             : struct mbuf *
    4178           0 : swofp_action_set_field(struct switch_softc *sc, struct mbuf *m,
    4179             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    4180             : {
    4181             :         struct ofp_oxm_class *oxm_handler;
    4182             :         struct ofp_action_set_field *oasf;
    4183             :         struct ofp_ox_match *oxm;
    4184             :         struct switch_flow_classify *swfcl, *pre_swfcl;
    4185             : 
    4186           0 :         oasf = (struct ofp_action_set_field *)oah;
    4187           0 :         oxm = (struct ofp_ox_match *)oasf->asf_field;
    4188             : 
    4189           0 :         oxm_handler = swofp_lookup_oxm_handler(oxm);
    4190           0 :         if ((oxm_handler == NULL) ||
    4191           0 :             (oxm_handler->oxm_set == NULL))
    4192             :                 goto failed;
    4193             : 
    4194           0 :         swfcl = swpld->swpld_swfcl;
    4195           0 :         pre_swfcl = &swpld->swpld_pre_swfcl;
    4196             : 
    4197           0 :         if (oxm->oxm_class == htons(OFP_OXM_C_NXM_1)) {
    4198           0 :                 switch (OFP_OXM_GET_FIELD(oxm)) {
    4199             :                 case OFP_XM_NXMT_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */
    4200             :                 case OFP_XM_NXMT_TUNNEL_IPV4_SRC:
    4201             :                 case OFP_XM_NXMT_TUNNEL_IPV4_DST:
    4202             :                 case OFP_XM_NXMT_TUNNEL_IPV6_SRC:
    4203             :                 case OFP_XM_NXMT_TUNNEL_IPV6_DST:
    4204           0 :                         if (pre_swfcl->swfcl_tunnel)
    4205             :                                 break;
    4206           0 :                         pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool,
    4207             :                             PR_NOWAIT|PR_ZERO);
    4208           0 :                         if (pre_swfcl->swfcl_tunnel == NULL)
    4209             :                                 goto failed;
    4210           0 :                         if (swfcl->swfcl_tunnel)
    4211           0 :                                 memcpy(pre_swfcl->swfcl_tunnel,
    4212             :                                     swfcl->swfcl_tunnel,
    4213             :                                     sizeof(*swfcl->swfcl_tunnel));
    4214             :                         break;
    4215             :                 }
    4216             :         } else {
    4217           0 :                 switch (OFP_OXM_GET_FIELD(oxm)) {
    4218             :                 case OFP_XM_T_ETH_SRC:
    4219             :                 case OFP_XM_T_ETH_DST:
    4220             :                 case OFP_XM_T_ETH_TYPE:
    4221           0 :                         if (pre_swfcl->swfcl_ether)
    4222             :                                 break;
    4223           0 :                         pre_swfcl->swfcl_ether = pool_get(&swfcl_pool,
    4224             :                             PR_NOWAIT|PR_ZERO);
    4225           0 :                         if (pre_swfcl->swfcl_ether == NULL)
    4226             :                                 goto failed;
    4227           0 :                         memcpy(pre_swfcl->swfcl_ether, swfcl->swfcl_ether,
    4228             :                             sizeof(*swfcl->swfcl_ether));
    4229           0 :                 break;
    4230             :                 case OFP_XM_T_VLAN_VID:
    4231             :                 case OFP_XM_T_VLAN_PCP:
    4232           0 :                         if (pre_swfcl->swfcl_vlan)
    4233             :                                 break;
    4234           0 :                         pre_swfcl->swfcl_vlan = pool_get(&swfcl_pool,
    4235             :                             PR_NOWAIT|PR_ZERO);
    4236           0 :                         if (pre_swfcl->swfcl_vlan == NULL)
    4237             :                                 goto failed;
    4238           0 :                         if (swfcl->swfcl_vlan)
    4239           0 :                                 memcpy(pre_swfcl->swfcl_vlan, swfcl->swfcl_vlan,
    4240             :                                     sizeof(*swfcl->swfcl_vlan));
    4241             :                         break;
    4242             :                 case OFP_XM_T_ARP_SHA:
    4243             :                 case OFP_XM_T_ARP_THA:
    4244             :                 case OFP_XM_T_ARP_SPA:
    4245             :                 case OFP_XM_T_ARP_TPA:
    4246             :                 case OFP_XM_T_ARP_OP:
    4247           0 :                         if (pre_swfcl->swfcl_arp)
    4248             :                                 break;
    4249           0 :                         pre_swfcl->swfcl_arp = pool_get(&swfcl_pool,
    4250             :                             PR_NOWAIT|PR_ZERO);
    4251           0 :                         if (swfcl->swfcl_arp == NULL)
    4252             :                                 goto failed;
    4253           0 :                         memcpy(pre_swfcl->swfcl_arp, swfcl->swfcl_arp,
    4254             :                             sizeof(*swfcl->swfcl_arp));
    4255           0 :                         break;
    4256             :                 case OFP_XM_T_IP_DSCP:
    4257             :                 case OFP_XM_T_IP_ECN:
    4258             :                 case OFP_XM_T_IP_PROTO:
    4259           0 :                         if (swfcl->swfcl_ipv4) {
    4260           0 :                                 if (pre_swfcl->swfcl_ipv4)
    4261             :                                         break;
    4262           0 :                                 pre_swfcl->swfcl_ipv4 = pool_get(&swfcl_pool,
    4263             :                                     PR_NOWAIT|PR_ZERO);
    4264           0 :                                 if (pre_swfcl->swfcl_ipv4 == NULL)
    4265             :                                         goto failed;
    4266           0 :                                 memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
    4267             :                                     sizeof(*swfcl->swfcl_ipv4));
    4268           0 :                         } else if (swfcl->swfcl_ipv6) {
    4269           0 :                                 if (pre_swfcl->swfcl_ipv6)
    4270             :                                         break;
    4271           0 :                                 pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool,
    4272             :                                     PR_NOWAIT|PR_ZERO);
    4273           0 :                                 if (pre_swfcl->swfcl_ipv6 == NULL)
    4274             :                                         goto failed;
    4275           0 :                                 memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
    4276             :                                     sizeof(*swfcl->swfcl_ipv6));
    4277           0 :                         }
    4278             :                         break;
    4279             :                 case OFP_XM_T_IPV4_SRC:
    4280             :                 case OFP_XM_T_IPV4_DST:
    4281           0 :                         if (pre_swfcl->swfcl_ipv4)
    4282             :                                 break;
    4283           0 :                         pre_swfcl->swfcl_ipv4 =  pool_get(&swfcl_pool,
    4284             :                             PR_NOWAIT|PR_ZERO);
    4285           0 :                         if (pre_swfcl->swfcl_ipv4 == NULL)
    4286             :                                 goto failed;
    4287           0 :                         memcpy(pre_swfcl->swfcl_ipv4, swfcl->swfcl_ipv4,
    4288             :                             sizeof(*swfcl->swfcl_ipv4));
    4289           0 :                         break;
    4290             :                 case OFP_XM_T_IPV6_SRC:
    4291             :                 case OFP_XM_T_IPV6_DST:
    4292             :                 case OFP_XM_T_IPV6_FLABEL:
    4293           0 :                         if (pre_swfcl->swfcl_ipv6)
    4294             :                                 break;
    4295           0 :                         pre_swfcl->swfcl_ipv6 = pool_get(&swfcl_pool,
    4296             :                             PR_NOWAIT|PR_ZERO);
    4297           0 :                         if (pre_swfcl->swfcl_ipv6 == NULL)
    4298             :                                 goto failed;
    4299           0 :                         memcpy(pre_swfcl->swfcl_ipv6, swfcl->swfcl_ipv6,
    4300             :                             sizeof(*swfcl->swfcl_ipv6));
    4301           0 :                         break;
    4302             :                 case OFP_XM_T_UDP_SRC:
    4303             :                 case OFP_XM_T_UDP_DST:
    4304           0 :                         if (pre_swfcl->swfcl_udp)
    4305             :                                 break;
    4306           0 :                         pre_swfcl->swfcl_udp = pool_get(&swfcl_pool,
    4307             :                             PR_NOWAIT|PR_ZERO);
    4308           0 :                         if (pre_swfcl->swfcl_udp == NULL)
    4309             :                                 goto failed;
    4310           0 :                         memcpy(pre_swfcl->swfcl_udp, swfcl->swfcl_udp,
    4311             :                             sizeof(*swfcl->swfcl_udp));
    4312           0 :                         break;
    4313             :                 case OFP_XM_T_TCP_SRC:
    4314             :                 case OFP_XM_T_TCP_DST:
    4315           0 :                         if (pre_swfcl->swfcl_tcp)
    4316             :                                 break;
    4317           0 :                         pre_swfcl->swfcl_tcp = pool_get(&swfcl_pool,
    4318             :                             PR_NOWAIT|PR_ZERO);
    4319           0 :                         if (pre_swfcl->swfcl_tcp == NULL)
    4320             :                                 goto failed;
    4321           0 :                         memcpy(pre_swfcl->swfcl_tcp, swfcl->swfcl_tcp,
    4322             :                             sizeof(*swfcl->swfcl_tcp));
    4323           0 :                         break;
    4324             :                 case OFP_XM_T_ICMPV4_CODE:
    4325             :                 case OFP_XM_T_ICMPV4_TYPE:
    4326           0 :                         if (pre_swfcl->swfcl_icmpv4)
    4327             :                                 break;
    4328           0 :                         pre_swfcl->swfcl_icmpv4 = pool_get(&swfcl_pool,
    4329             :                             PR_NOWAIT|PR_ZERO);
    4330           0 :                         if (pre_swfcl->swfcl_icmpv4 == NULL)
    4331             :                                 goto failed;
    4332           0 :                         memcpy(pre_swfcl->swfcl_icmpv4, swfcl->swfcl_icmpv4,
    4333             :                             sizeof(*swfcl->swfcl_icmpv4));
    4334           0 :                         break;
    4335             :                 case OFP_XM_T_ICMPV6_CODE:
    4336             :                 case OFP_XM_T_ICMPV6_TYPE:
    4337           0 :                         if (pre_swfcl->swfcl_icmpv6)
    4338             :                                 break;
    4339           0 :                         pre_swfcl->swfcl_icmpv6 = pool_get(&swfcl_pool,
    4340             :                             PR_NOWAIT|PR_ZERO);
    4341           0 :                         if (pre_swfcl->swfcl_icmpv6 == NULL)
    4342             :                                 goto failed;
    4343           0 :                         memcpy(pre_swfcl->swfcl_icmpv6, swfcl->swfcl_icmpv6,
    4344             :                             sizeof(*swfcl->swfcl_icmpv6));
    4345           0 :                         break;
    4346             :                 case OFP_XM_T_IPV6_ND_SLL:
    4347             :                 case OFP_XM_T_IPV6_ND_TLL:
    4348             :                 case OFP_XM_T_IPV6_ND_TARGET:
    4349           0 :                         if (pre_swfcl->swfcl_nd6)
    4350             :                                 break;
    4351           0 :                         pre_swfcl->swfcl_nd6 = pool_get(&swfcl_pool,
    4352             :                             PR_NOWAIT|PR_ZERO);
    4353           0 :                         if (pre_swfcl->swfcl_nd6 == NULL)
    4354             :                                 goto failed;
    4355           0 :                         memcpy(pre_swfcl->swfcl_nd6, swfcl->swfcl_nd6,
    4356             :                             sizeof(*swfcl->swfcl_nd6));
    4357           0 :                         break;
    4358             :                 case OFP_XM_T_TUNNEL_ID: /* alias OFP_XM_T_TUNNEL_ID */
    4359           0 :                         if (pre_swfcl->swfcl_tunnel)
    4360             :                                 break;
    4361           0 :                         pre_swfcl->swfcl_tunnel = pool_get(&swfcl_pool,
    4362             :                             PR_NOWAIT|PR_ZERO);
    4363           0 :                         if (pre_swfcl->swfcl_tunnel == NULL)
    4364             :                                 goto failed;
    4365           0 :                         if (swfcl->swfcl_tunnel)
    4366           0 :                                 memcpy(pre_swfcl->swfcl_tunnel,
    4367             :                                     swfcl->swfcl_tunnel,
    4368             :                                     sizeof(*swfcl->swfcl_tunnel));
    4369             :                         break;
    4370             :                 }
    4371             :         }
    4372             : 
    4373           0 :         if (oxm_handler->oxm_set(pre_swfcl, oxm))
    4374             :                 goto failed;
    4375             : 
    4376           0 :         return (m);
    4377             :  failed:
    4378           0 :         m_freem(m);
    4379           0 :         return (NULL);
    4380           0 : }
    4381             : 
    4382             : struct mbuf *
    4383           0 : swofp_execute_action(struct switch_softc *sc, struct mbuf *m,
    4384             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    4385             : {
    4386             :         struct ofp_action_handler       *handler;
    4387             : 
    4388           0 :         handler = swofp_lookup_action_handler(ntohs(oah->ah_type));
    4389           0 :         if ((handler == NULL) || (handler->action == NULL)) {
    4390             :                 DPRINTF(sc, "unknown action (type %d)\n",
    4391             :                     ntohs(oah->ah_type));
    4392           0 :                 m_freem(m);
    4393           0 :                 return (NULL);
    4394             :         }
    4395             : 
    4396           0 :         m = handler->action(sc, m, swpld, oah);
    4397           0 :         if (m == NULL)
    4398           0 :                 return (NULL);
    4399             : 
    4400           0 :         return (m);
    4401           0 : }
    4402             : 
    4403             : struct mbuf *
    4404           0 : swofp_execute_action_set_field(struct switch_softc *sc, struct mbuf *m,
    4405             :     struct swofp_pipeline_desc *swpld, struct ofp_action_header *oah)
    4406             : {
    4407             :         struct ofp_action_header        **set_fields;
    4408             :         int i;
    4409             : 
    4410           0 :         set_fields = (struct ofp_action_header **)oah;
    4411             : 
    4412           0 :         for (i = 0; i < OFP_XM_T_MAX; i++) {
    4413           0 :                 if (set_fields[i] == NULL)
    4414             :                         continue;
    4415             : 
    4416           0 :                 m = swofp_execute_action(sc, m, swpld, set_fields[i]);
    4417           0 :                 if (m == NULL)
    4418           0 :                         return (NULL);
    4419             :         }
    4420             : 
    4421           0 :         return (m);
    4422           0 : }
    4423             : 
    4424             : 
    4425             : struct mbuf *
    4426           0 : swofp_execute_action_set(struct switch_softc *sc, struct mbuf *m,
    4427             :     struct swofp_pipeline_desc *swpld)
    4428             : {
    4429             :         struct swofp_action_set *swas;
    4430             :         int                      i;
    4431             : 
    4432           0 :         TAILQ_INIT(&swpld->swpld_fwdp_q);
    4433           0 :         swas = swpld->swpld_action_set;
    4434           0 :         swpld->swpld_swfcl->swfcl_cookie = UINT64_MAX;
    4435             : 
    4436           0 :         for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
    4437           0 :                 if (swas[i].swas_action == NULL)
    4438             :                         continue;
    4439             : 
    4440           0 :                 if (swas[i].swas_type == OFP_ACTION_SET_FIELD)
    4441           0 :                         m = swofp_execute_action_set_field(sc, m, swpld,
    4442             :                             swas[i].swas_action);
    4443             :                 else
    4444           0 :                         m = swofp_execute_action(sc, m, swpld,
    4445             :                             swas[i].swas_action);
    4446             : 
    4447           0 :                 if (m == NULL)
    4448             :                         break;
    4449             :         }
    4450             : 
    4451           0 :         m_freem(m);
    4452             : 
    4453           0 :         return (NULL);
    4454             : }
    4455             : 
    4456             : struct mbuf *
    4457           0 : swofp_apply_actions(struct switch_softc *sc, struct mbuf *m,
    4458             :     struct swofp_pipeline_desc *swpld, struct ofp_instruction_actions *oia)
    4459             : {
    4460             :         struct ofp_action_header        *oah;
    4461             : 
    4462           0 :         TAILQ_INIT(&swpld->swpld_fwdp_q);
    4463             : 
    4464           0 :         OFP_I_ACTIONS_FOREACH(oia, oah) {
    4465           0 :                 m = swofp_execute_action(sc, m, swpld, oah);
    4466           0 :                 if (m == NULL)
    4467           0 :                         return (NULL);
    4468             :         }
    4469             : 
    4470           0 :         return (m);
    4471           0 : }
    4472             : 
    4473             : struct swofp_action_set *
    4474           0 : swofp_lookup_action_set(struct swofp_pipeline_desc *swpld, uint16_t type)
    4475             : {
    4476             :         int     i;
    4477             : 
    4478           0 :         for (i = 0; i < nitems(ofp_action_handlers); i ++) {
    4479           0 :                 if (swpld->swpld_action_set[i].swas_type == type)
    4480           0 :                         return (&swpld->swpld_action_set[i]);
    4481             :         }
    4482             : 
    4483           0 :         return (NULL);
    4484           0 : }
    4485             : 
    4486             : void
    4487           0 : swofp_write_actions_set_field(struct swofp_action_set *swas,
    4488             :     struct ofp_action_header *oah)
    4489             : {
    4490             :         struct ofp_action_header        **set_fields;
    4491             :         struct ofp_action_set_field     *oasf;
    4492             :         struct ofp_ox_match             *oxm;
    4493             : 
    4494           0 :         set_fields = (struct ofp_action_header **)swas->swas_action;
    4495             : 
    4496           0 :         oasf = (struct ofp_action_set_field *)oah;
    4497           0 :         oxm = (struct ofp_ox_match *)oasf->asf_field;
    4498             : 
    4499           0 :         set_fields[OFP_OXM_GET_FIELD(oxm)] = oah;
    4500           0 : }
    4501             : 
    4502             : int
    4503           0 : swofp_write_actions(struct ofp_instruction_actions *oia,
    4504             :     struct swofp_pipeline_desc *swpld)
    4505             : {
    4506             :         struct swofp_action_set         *swas;
    4507             :         struct ofp_action_header        *oah;
    4508             : 
    4509           0 :         OFP_I_ACTIONS_FOREACH(oia, oah) {
    4510           0 :                 swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type));
    4511           0 :                 if (swas == NULL)
    4512           0 :                         return (ENOENT);
    4513             : 
    4514           0 :                 if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD)
    4515           0 :                         swofp_write_actions_set_field(swas, oah);
    4516             :                 else
    4517           0 :                         swas->swas_action = oah;
    4518             :         }
    4519             : 
    4520           0 :         return (0);
    4521           0 : }
    4522             : 
    4523             : void
    4524           0 : swofp_clear_actions_set_field(struct swofp_action_set *swas,
    4525             :     struct ofp_action_header *oah)
    4526             : {
    4527             :         struct ofp_action_header        **set_fields;
    4528             :         struct ofp_action_set_field     *oasf;
    4529             :         struct ofp_ox_match             *oxm;
    4530             : 
    4531           0 :         set_fields = (struct ofp_action_header **)swas->swas_action;
    4532             : 
    4533           0 :         oasf = (struct ofp_action_set_field *)oah;
    4534           0 :         oxm = (struct ofp_ox_match *)oasf->asf_field;
    4535             : 
    4536           0 :         set_fields[OFP_OXM_GET_FIELD(oxm)] = NULL;
    4537           0 : }
    4538             : 
    4539             : int
    4540           0 : swofp_clear_actions(struct ofp_instruction_actions *oia,
    4541             :     struct swofp_pipeline_desc *swpld)
    4542             : {
    4543             :         struct swofp_action_set         *swas;
    4544             :         struct ofp_action_header        *oah;
    4545             : 
    4546           0 :         OFP_I_ACTIONS_FOREACH(oia, oah) {
    4547           0 :                 swas = swofp_lookup_action_set(swpld, ntohs(oah->ah_type));
    4548           0 :                 if (swas == NULL)
    4549           0 :                         return (ENOENT);
    4550             : 
    4551           0 :                 if (ntohs(oah->ah_type) == OFP_ACTION_SET_FIELD)
    4552           0 :                         swofp_clear_actions_set_field(swas, oah);
    4553             :                 else
    4554           0 :                         swas->swas_action = NULL;
    4555             :         }
    4556             : 
    4557           0 :         return (0);
    4558           0 : }
    4559             : 
    4560             : void
    4561           0 : swofp_write_metadata(struct ofp_instruction_write_metadata *iowm,
    4562             :     struct swofp_pipeline_desc *swpld)
    4563             : {
    4564             :         uint64_t val, mask;
    4565             : 
    4566           0 :         val = iowm->iwm_metadata;
    4567           0 :         mask = iowm->iwm_metadata_mask;
    4568             : 
    4569           0 :         swpld->swpld_metadata = (val & mask);
    4570           0 : }
    4571             : 
    4572             : void
    4573           0 : swofp_forward_ofs(struct switch_softc *sc, struct switch_flow_classify *swfcl,
    4574             :     struct mbuf *m)
    4575             : {
    4576           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    4577             :         struct swofp_flow_entry         *swfe;
    4578             :         struct swofp_flow_table         *swft;
    4579             :         struct swofp_pipeline_desc      *swpld;
    4580             :         int                              error;
    4581             :         uint8_t                          next_table_id = 0;
    4582             : 
    4583           0 :         swpld = swofp_pipeline_desc_create(swfcl);
    4584           0 :         if (swpld == NULL) {
    4585           0 :                 m_freem(m);
    4586           0 :                 return;
    4587             :         }
    4588             : 
    4589           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    4590           0 :                 if (swft->swft_table_id != next_table_id)
    4591             :                         continue;
    4592             : 
    4593             :                 /* XXX
    4594             :                  * The metadata is pipeline parameters but it uses same match
    4595             :                  * framework for matching so it is copy to flow classify.
    4596             :                  */
    4597           0 :                 swpld->swpld_swfcl->swfcl_metadata = swpld->swpld_metadata;
    4598             : 
    4599           0 :                 if ((swfe = swofp_flow_lookup(swft,
    4600           0 :                     swpld->swpld_swfcl)) == NULL)
    4601             :                         break;
    4602             : 
    4603             :                 /* Set pipeline parameters */
    4604           0 :                 swpld->swpld_cookie = swfe->swfe_cookie;
    4605           0 :                 swpld->swpld_table_id = swft->swft_table_id;
    4606           0 :                 swpld->swpld_tablemiss = swfe->swfe_tablemiss;
    4607             : 
    4608             :                 /* Update statistics */
    4609           0 :                 nanouptime(&swfe->swfe_idle_time);
    4610           0 :                 swfe->swfe_packet_cnt++;
    4611           0 :                 swfe->swfe_byte_cnt += m->m_pkthdr.len;
    4612             : 
    4613           0 :                 if (swfe->swfe_meter) {
    4614             :                         /* TODO: Here is meter instruction */
    4615             :                 }
    4616             : 
    4617           0 :                 if (swfe->swfe_apply_actions) {
    4618           0 :                         m = swofp_apply_actions(sc, m, swpld,
    4619             :                             swfe->swfe_apply_actions);
    4620           0 :                         if (m == NULL)
    4621             :                                 goto out;
    4622             :                 }
    4623             : 
    4624           0 :                 if (swfe->swfe_clear_actions) {
    4625           0 :                         error = swofp_clear_actions(
    4626             :                             swfe->swfe_clear_actions, swpld);
    4627           0 :                         if (error)
    4628             :                                 goto out;
    4629             :                 }
    4630             : 
    4631           0 :                 if (swfe->swfe_write_actions) {
    4632           0 :                         error = swofp_write_actions(
    4633             :                             swfe->swfe_write_actions, swpld);
    4634           0 :                         if (error)
    4635             :                                 goto out;
    4636             :                 }
    4637             : 
    4638           0 :                 if (swfe->swfe_write_metadata)
    4639           0 :                         swofp_write_metadata(swfe->swfe_write_metadata, swpld);
    4640             : 
    4641           0 :                 if (swfe->swfe_goto_table)
    4642           0 :                         next_table_id = swfe->swfe_goto_table->igt_table_id;
    4643             :                 else
    4644             :                         break;
    4645           0 :         }
    4646             : 
    4647           0 :         m = swofp_execute_action_set(sc, m, swpld);
    4648             :  out:
    4649           0 :         m_freem(m);
    4650           0 :         swofp_pipeline_desc_destroy(swpld);
    4651           0 : }
    4652             : 
    4653             : int
    4654           0 : swofp_input(struct switch_softc *sc, struct mbuf *m)
    4655             : {
    4656           0 :         struct swofp_ofs        *swofs = sc->sc_ofs;
    4657             :         struct ofp_header       *oh;
    4658             :         ofp_msg_handler          handler;
    4659             :         uint16_t                 ohlen;
    4660             : 
    4661           0 :         if (m->m_len < sizeof(*oh) &&
    4662           0 :             (m = m_pullup(m, sizeof(*oh))) == NULL)
    4663           0 :                 return (ENOBUFS);
    4664             : 
    4665           0 :         oh = mtod(m, struct ofp_header *);
    4666             : 
    4667           0 :         ohlen = ntohs(oh->oh_length);
    4668             :         /* Validate that we have a sane header. */
    4669           0 :         if (ohlen < sizeof(*oh)) {
    4670           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    4671             :                     OFP_ERRREQ_BAD_LEN);
    4672           0 :                 return (0);
    4673             :         }
    4674             : 
    4675           0 :         if (m->m_len < ohlen && (m = m_pullup(m, ohlen)) == NULL)
    4676           0 :                 return (ENOBUFS);
    4677             : 
    4678             : #if NBPFILTER > 0
    4679           0 :         if (sc->sc_ofbpf)
    4680           0 :                 switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_IN,
    4681           0 :                     swofs->swofs_datapath_id);
    4682             : #endif
    4683             : 
    4684           0 :         handler = swofp_lookup_msg_handler(oh->oh_type);
    4685           0 :         if (handler)
    4686           0 :                 (*handler)(sc, m);
    4687             :         else
    4688           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    4689             :                     OFP_ERRREQ_TYPE);
    4690             : 
    4691           0 :         return (0);
    4692           0 : }
    4693             : 
    4694             : int
    4695           0 : swofp_output(struct switch_softc *sc, struct mbuf *m)
    4696             : {
    4697           0 :         struct swofp_ofs        *swofs = sc->sc_ofs;
    4698             : 
    4699           0 :         if (sc->sc_swdev == NULL) {
    4700           0 :                 m_freem(m);
    4701           0 :                 return (ENXIO);
    4702             :         }
    4703             : 
    4704             : #if NBPFILTER > 0
    4705           0 :         if (sc->sc_ofbpf)
    4706           0 :                 switch_mtap(sc->sc_ofbpf, m, BPF_DIRECTION_OUT,
    4707           0 :                     swofs->swofs_datapath_id);
    4708             : #endif
    4709             : 
    4710           0 :         if (sc->sc_swdev->swdev_output(sc, m) != 0)
    4711           0 :                 return (ENOBUFS);
    4712             : 
    4713           0 :         return (0);
    4714           0 : }
    4715             : 
    4716             : /*
    4717             :  * OpenFlow protocol HELLO message handler
    4718             :  */
    4719             : int
    4720           0 : swofp_recv_hello(struct switch_softc *sc, struct mbuf *m)
    4721             : {
    4722             :         struct ofp_header       *oh;
    4723             : 
    4724           0 :         oh = mtod(m, struct ofp_header *);
    4725             : 
    4726           0 :         if (oh->oh_version != OFP_V_1_3)
    4727           0 :                 swofp_send_error(sc, m,
    4728             :                     OFP_ERRTYPE_HELLO_FAILED, OFP_ERRHELLO_INCOMPATIBLE);
    4729             :         else
    4730           0 :                 m_freem(m);
    4731             : 
    4732           0 :         return (0);
    4733             : }
    4734             : 
    4735             : void
    4736           0 : swofp_send_hello(struct switch_softc *sc)
    4737             : {
    4738           0 :         struct swofp_ofs                *swofs = sc->sc_ofs;
    4739             :         struct mbuf                     *m;
    4740             :         struct ofp_header               *oh;
    4741             : 
    4742           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    4743           0 :         if (m == NULL)
    4744           0 :                 return;         /* XXX */
    4745             : 
    4746           0 :         oh = mtod(m, struct ofp_header *);
    4747             : 
    4748           0 :         oh->oh_version = OFP_V_1_3;
    4749           0 :         oh->oh_type = OFP_T_HELLO;
    4750           0 :         oh->oh_length = htons(sizeof(*oh));
    4751           0 :         oh->oh_xid = htonl(swofs->swofs_xidnxt++);
    4752           0 :         m->m_len = m->m_pkthdr.len = sizeof(*oh);
    4753             : 
    4754           0 :         (void)swofp_output(sc, m);
    4755           0 : }
    4756             : 
    4757             : /*
    4758             :  * OpenFlow protocol Error message
    4759             :  */
    4760             : void
    4761           0 : swofp_send_error(struct switch_softc *sc, struct mbuf *m,
    4762             :     uint16_t type, uint16_t code)
    4763             : {
    4764             :         struct ofp_error        *oe;
    4765             :         uint16_t                 len;
    4766           0 :         uint8_t                  data[OFP_ERRDATA_MAX];
    4767             : 
    4768             :         /* Reuse mbuf from request message */
    4769           0 :         oe = mtod(m, struct ofp_error *);
    4770             : 
    4771             :         /* Save data for the response and copy back later. */
    4772           0 :         len = min(ntohs(oe->err_oh.oh_length), OFP_ERRDATA_MAX);
    4773           0 :         m_copydata(m, 0, len, data);
    4774             : 
    4775           0 :         oe->err_oh.oh_version = OFP_V_1_3;
    4776           0 :         oe->err_oh.oh_type = OFP_T_ERROR;
    4777           0 :         oe->err_type = htons(type);
    4778           0 :         oe->err_code = htons(code);
    4779           0 :         oe->err_oh.oh_length = htons(len + sizeof(struct ofp_error));
    4780           0 :         m->m_len = m->m_pkthdr.len = sizeof(struct ofp_error);
    4781             : 
    4782           0 :         if (m_copyback(m, sizeof(struct ofp_error), len, data, M_DONTWAIT)) {
    4783           0 :                 m_freem(m);
    4784           0 :                 return;
    4785             :         }
    4786             : 
    4787           0 :         (void)swofp_output(sc, m);
    4788           0 : }
    4789             : 
    4790             : 
    4791             : /*
    4792             :  * OpenFlow protocol Echo message
    4793             :  */
    4794             : int
    4795           0 : swofp_recv_echo(struct switch_softc *sc, struct mbuf *m)
    4796             : {
    4797           0 :         return swofp_send_echo(sc, m);
    4798             : }
    4799             : 
    4800             : int
    4801           0 : swofp_send_echo(struct switch_softc *sc, struct mbuf *m)
    4802             : {
    4803             :         struct ofp_header       *oh;
    4804             : 
    4805           0 :         oh = mtod(m, struct ofp_header *);
    4806           0 :         oh->oh_type = OFP_T_ECHO_REPLY;
    4807             : 
    4808           0 :         return (swofp_output(sc, m));
    4809             : }
    4810             : 
    4811             : 
    4812             : /*
    4813             :  * Feature request handler
    4814             :  */
    4815             : int
    4816           0 : swofp_recv_features_req(struct switch_softc *sc, struct mbuf *m)
    4817             : {
    4818             : 
    4819           0 :         struct swofp_ofs                *swofs = sc->sc_ofs;
    4820             :         struct ofp_header               *oh;
    4821           0 :         struct ofp_switch_features       swf;
    4822             : 
    4823           0 :         oh = mtod(m, struct ofp_header *);
    4824             : 
    4825           0 :         memset(&swf, 0, sizeof(swf));
    4826           0 :         memcpy(&swf, oh, sizeof(*oh));
    4827           0 :         swf.swf_oh.oh_type = OFP_T_FEATURES_REPLY;
    4828           0 :         swf.swf_oh.oh_length = htons(sizeof(swf));
    4829             : 
    4830           0 :         swf.swf_datapath_id = htobe64(swofs->swofs_datapath_id);
    4831           0 :         swf.swf_nbuffers = htonl(0); /* no buffer now */
    4832           0 :         swf.swf_ntables = OFP_TABLE_ID_MAX;
    4833           0 :         swf.swf_aux_id = 0;
    4834           0 :         swf.swf_capabilities = htonl(OFP_SWCAP_FLOW_STATS |
    4835             :             OFP_SWCAP_TABLE_STATS | OFP_SWCAP_PORT_STATS |
    4836             :             OFP_SWCAP_GROUP_STATS);
    4837             : 
    4838           0 :         m_copyback(m, 0, sizeof(swf), (caddr_t)&swf, M_WAIT);
    4839             : 
    4840           0 :         return (swofp_output(sc, m));
    4841           0 : }
    4842             : 
    4843             : /*
    4844             :  * Get config handler
    4845             :  */
    4846             : int
    4847           0 : swofp_recv_config_req(struct switch_softc *sc, struct mbuf *m)
    4848             : {
    4849           0 :         struct swofp_ofs                *swofs = sc->sc_ofs;
    4850           0 :         struct ofp_switch_config         osc;
    4851             : 
    4852           0 :         memcpy(&osc.cfg_oh, mtod(m, caddr_t), sizeof(struct ofp_header));
    4853           0 :         osc.cfg_oh.oh_type = OFP_T_GET_CONFIG_REPLY;
    4854           0 :         osc.cfg_oh.oh_length = htons(sizeof(osc));
    4855             : 
    4856           0 :         osc.cfg_flags = htons(swofs->swofs_switch_config.cfg_flags);
    4857           0 :         osc.cfg_miss_send_len =
    4858           0 :             htons(swofs->swofs_switch_config.cfg_miss_send_len);
    4859           0 :         if (m_copyback(m, 0, sizeof(osc), &osc, M_NOWAIT)) {
    4860           0 :                 m_freem(m);
    4861           0 :                 return (-1);
    4862             :         }
    4863             : 
    4864           0 :         return (swofp_output(sc, m));
    4865           0 : }
    4866             : 
    4867             : /*
    4868             :  * Set config handler
    4869             :  */
    4870             : int
    4871           0 : swofp_recv_set_config(struct switch_softc *sc, struct mbuf *m)
    4872             : {
    4873           0 :         struct swofp_ofs                *swofs = sc->sc_ofs;
    4874             :         struct ofp_switch_config        *swc;
    4875             : 
    4876           0 :         swc = mtod(m, struct ofp_switch_config *);
    4877           0 :         if (ntohs(swc->cfg_oh.oh_length) < sizeof(*swc)) {
    4878           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    4879             :                     OFP_ERRREQ_BAD_LEN);
    4880           0 :                 return (-1);
    4881             :         }
    4882             : 
    4883             :         /*
    4884             :          * Support only "normal" fragment handle
    4885             :          */
    4886           0 :         swofs->swofs_switch_config.cfg_flags = OFP_CONFIG_FRAG_NORMAL;
    4887           0 :         swofs->swofs_switch_config.cfg_miss_send_len =
    4888           0 :             ntohs(swc->cfg_miss_send_len);
    4889             : 
    4890           0 :         m_freem(m);
    4891             : 
    4892           0 :         return (0);
    4893           0 : }
    4894             : 
    4895             : /*
    4896             :  * OpenFlow protocol FLOW REMOVE message handlers
    4897             :  */
    4898             : int
    4899           0 : swofp_send_flow_removed(struct switch_softc *sc, struct swofp_flow_entry *swfe,
    4900             :     uint8_t reason)
    4901             : {
    4902             :         struct ofp_flow_removed *ofr;
    4903           0 :         struct timespec          now, duration;
    4904             :         struct mbuf             *m;
    4905             :         int                      match_len;
    4906             : 
    4907           0 :         match_len = ntohs(swfe->swfe_match->om_length);
    4908             : 
    4909           0 :         MGETHDR(m, M_WAITOK, MT_DATA);
    4910           0 :         if (m == NULL)
    4911           0 :                 return (ENOBUFS);
    4912           0 :         if ((sizeof(*ofr) + match_len) >= MHLEN) {
    4913           0 :                 MCLGET(m, M_WAITOK);
    4914           0 :                 if ((m->m_flags & M_EXT) == 0) {
    4915           0 :                         m_freem(m);
    4916           0 :                         return (ENOBUFS);
    4917             :                 }
    4918             :         }
    4919             : 
    4920           0 :         ofr = mtod(m, struct ofp_flow_removed *);
    4921             : 
    4922           0 :         ofr->fr_oh.oh_version = OFP_V_1_3;
    4923           0 :         ofr->fr_oh.oh_type = OFP_T_FLOW_REMOVED;
    4924           0 :         ofr->fr_oh.oh_xid = htonl(sc->sc_ofs->swofs_xidnxt++);
    4925             : 
    4926           0 :         ofr->fr_cookie = htobe64(swfe->swfe_cookie);
    4927           0 :         ofr->fr_priority = htons(swfe->swfe_priority);
    4928           0 :         ofr->fr_reason = reason;
    4929           0 :         ofr->fr_table_id = swfe->swfe_table_id;
    4930             : 
    4931           0 :         nanouptime(&now);
    4932           0 :         timespecsub(&now, &swfe->swfe_installed_time, &duration);
    4933           0 :         ofr->fr_duration_sec = ntohl((int)duration.tv_sec);
    4934           0 :         ofr->fr_priority = htons(swfe->swfe_priority);
    4935           0 :         ofr->fr_idle_timeout = htons(swfe->swfe_idle_timeout);
    4936           0 :         ofr->fr_hard_timeout = htons(swfe->swfe_hard_timeout);
    4937           0 :         ofr->fr_byte_count = htobe64(swfe->swfe_byte_cnt);
    4938           0 :         ofr->fr_packet_count = htobe64(swfe->swfe_packet_cnt);
    4939             : 
    4940           0 :         memcpy(&ofr->fr_match, swfe->swfe_match, match_len);
    4941             : 
    4942             :         /* match_len inclusive ofp_match header length*/
    4943           0 :         ofr->fr_oh.oh_length =
    4944           0 :             htons(sizeof(*ofr) + match_len - sizeof(struct ofp_match));
    4945             : 
    4946           0 :         m->m_len = m->m_pkthdr.len =
    4947           0 :             sizeof(*ofr) + match_len - sizeof(struct ofp_match);
    4948             : 
    4949           0 :         return (swofp_output(sc, m));
    4950           0 : }
    4951             : 
    4952             : /*
    4953             :  * OpenFlow protocol FLOW MOD message handlers
    4954             :  */
    4955             : int
    4956           0 : swofp_flow_entry_put_instructions(struct switch_softc *sc, struct mbuf *m,
    4957             :     struct swofp_flow_entry *swfe, uint16_t *etype, uint16_t *error)
    4958             : {
    4959             :         struct ofp_flow_mod     *ofm;
    4960             :         struct ofp_instruction  *oi;
    4961             :         caddr_t                  inst;
    4962             :         int                      start, len, off;
    4963             : 
    4964           0 :         *etype = OFP_ERRTYPE_BAD_INSTRUCTION;
    4965             : 
    4966           0 :         ofm = mtod(m, struct ofp_flow_mod *);
    4967             : 
    4968             :         /*
    4969             :          * Clear instructions from flow entry. It's necessary to only modify
    4970             :          * flow but it's no problem to clear on adding flow because the flow
    4971             :          * entry doesn't have any instructions. So it's always called.
    4972             :          */
    4973           0 :         swofp_flow_entry_instruction_free(swfe);
    4974             : 
    4975           0 :         start = OFP_FLOW_MOD_MSG_INSTRUCTION_OFFSET(ofm);
    4976           0 :         len = ntohs(ofm->fm_oh.oh_length) - start;
    4977           0 :         for (off = start; off < start + len; off += ntohs(oi->i_len)) {
    4978           0 :                 oi = (struct ofp_instruction *)(mtod(m, caddr_t) + off);
    4979             : 
    4980           0 :                 if (swofp_validate_flow_instruction(sc, oi,
    4981           0 :                     len - (off - start), etype, error))
    4982           0 :                         return (-1);
    4983             : 
    4984           0 :                 if ((inst = malloc(ntohs(oi->i_len), M_DEVBUF,
    4985           0 :                     M_DONTWAIT|M_ZERO)) == NULL) {
    4986           0 :                         *error = OFP_ERRFLOWMOD_UNKNOWN;
    4987           0 :                         return (-1);
    4988             :                 }
    4989           0 :                 memcpy(inst, oi, ntohs(oi->i_len));
    4990             : 
    4991           0 :                 switch (ntohs(oi->i_type)) {
    4992             :                 case OFP_INSTRUCTION_T_GOTO_TABLE:
    4993           0 :                         if (swfe->swfe_goto_table)
    4994           0 :                                 free(swfe->swfe_goto_table, M_DEVBUF,
    4995           0 :                                     ntohs(swfe->swfe_goto_table->igt_len));
    4996             : 
    4997           0 :                         swfe->swfe_goto_table =
    4998           0 :                             (struct ofp_instruction_goto_table *)inst;
    4999           0 :                         break;
    5000             :                 case OFP_INSTRUCTION_T_WRITE_META:
    5001           0 :                         if (swfe->swfe_write_metadata)
    5002           0 :                                 free(swfe->swfe_write_metadata, M_DEVBUF,
    5003           0 :                                     ntohs(swfe->swfe_write_metadata->iwm_len));
    5004             : 
    5005           0 :                         swfe->swfe_write_metadata =
    5006           0 :                             (struct ofp_instruction_write_metadata *)inst;
    5007           0 :                         break;
    5008             :                 case OFP_INSTRUCTION_T_WRITE_ACTIONS:
    5009           0 :                         if (swfe->swfe_write_actions)
    5010           0 :                                 free(swfe->swfe_write_actions, M_DEVBUF,
    5011           0 :                                     ntohs(swfe->swfe_write_actions->ia_len));
    5012             : 
    5013           0 :                         swfe->swfe_write_actions =
    5014           0 :                             (struct ofp_instruction_actions *)inst;
    5015           0 :                         break;
    5016             :                 case OFP_INSTRUCTION_T_APPLY_ACTIONS:
    5017           0 :                         if (swfe->swfe_apply_actions)
    5018           0 :                                 free(swfe->swfe_apply_actions, M_DEVBUF,
    5019           0 :                                     ntohs(swfe->swfe_apply_actions->ia_len));
    5020             : 
    5021           0 :                         swfe->swfe_apply_actions =
    5022           0 :                             (struct ofp_instruction_actions *)inst;
    5023           0 :                         break;
    5024             :                 case OFP_INSTRUCTION_T_CLEAR_ACTIONS:
    5025           0 :                         if (swfe->swfe_clear_actions)
    5026           0 :                                 free(swfe->swfe_clear_actions, M_DEVBUF,
    5027           0 :                                     ntohs(swfe->swfe_clear_actions->ia_len));
    5028             : 
    5029           0 :                         swfe->swfe_clear_actions =
    5030           0 :                             (struct ofp_instruction_actions *)inst;
    5031           0 :                         break;
    5032             :                 case OFP_INSTRUCTION_T_METER:
    5033           0 :                         if (swfe->swfe_meter)
    5034           0 :                                 free(swfe->swfe_meter, M_DEVBUF,
    5035           0 :                                     ntohs(swfe->swfe_meter->im_len));
    5036             : 
    5037           0 :                         swfe->swfe_meter = (struct ofp_instruction_meter *)inst;
    5038           0 :                         break;
    5039             :                 case OFP_INSTRUCTION_T_EXPERIMENTER:
    5040           0 :                         if (swfe->swfe_experimenter)
    5041           0 :                                 free(swfe->swfe_experimenter, M_DEVBUF,
    5042           0 :                                     ntohs(swfe->swfe_experimenter->ie_len));
    5043             : 
    5044           0 :                         swfe->swfe_experimenter =
    5045           0 :                             (struct ofp_instruction_experimenter *)inst;
    5046           0 :                         break;
    5047             :                 default:
    5048           0 :                         free(inst, M_DEVBUF, ntohs(oi->i_len));
    5049           0 :                         break;
    5050             :                 }
    5051             :         }
    5052             : 
    5053           0 :         return (0);
    5054           0 : }
    5055             : 
    5056             : int
    5057           0 : swofp_flow_mod_cmd_add(struct switch_softc *sc, struct mbuf *m)
    5058             : {
    5059           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    5060             :         struct ofp_flow_mod             *ofm;
    5061             :         struct ofp_match                *om;
    5062           0 :         struct swofp_flow_entry         *swfe, *old_swfe;
    5063             :         struct swofp_flow_table         *swft;
    5064             :         int                              omlen;
    5065           0 :         uint16_t                         error, etype;
    5066             : 
    5067           0 :         etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
    5068           0 :         ofm = mtod(m, struct ofp_flow_mod *);
    5069           0 :         om = &ofm->fm_match;
    5070             : 
    5071           0 :         if (OFP_TABLE_ID_MAX < ofm->fm_table_id) {
    5072           0 :                 error = OFP_ERRFLOWMOD_TABLE_ID;
    5073           0 :                 goto ofp_error;
    5074             :         }
    5075             : 
    5076           0 :         if (ofm->fm_cookie == UINT64_MAX) {
    5077             :                  /* XXX What is best error code? */
    5078           0 :                 error = OFP_ERRFLOWMOD_UNKNOWN;
    5079           0 :                 goto ofp_error;
    5080             :         }
    5081             : 
    5082           0 :         omlen = ntohs(om->om_length);
    5083             :         /*
    5084             :          * 1) ofp_match header must have at least its own size,
    5085             :          *    otherwise memcpy() will fail later;
    5086             :          * 2) OXM filters can't be bigger than the packet.
    5087             :          */
    5088           0 :         if (omlen < sizeof(*om) ||
    5089           0 :             omlen >= (m->m_len - sizeof(*ofm))) {
    5090           0 :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5091           0 :                 error = OFP_ERRMATCH_BAD_LEN;
    5092           0 :                 goto ofp_error;
    5093             :         }
    5094             : 
    5095           0 :         if ((swft = swofp_flow_table_add(sc, ofm->fm_table_id)) == NULL) {
    5096           0 :                 error = OFP_ERRFLOWMOD_TABLE_ID;
    5097           0 :                 goto ofp_error;
    5098             :         }
    5099             : 
    5100           0 :         if (swft->swft_flow_num >= ofs->swofs_flow_max_entry) {
    5101           0 :                 error = OFP_ERRFLOWMOD_TABLE_FULL;
    5102           0 :                 goto ofp_error;
    5103             :         }
    5104             : 
    5105             :         /* Validate that the OXM are in-place and correct. */
    5106           0 :         if (swofp_validate_flow_match(om, &error)) {
    5107           0 :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5108           0 :                 goto ofp_error;
    5109             :         }
    5110             : 
    5111           0 :         if ((old_swfe = swofp_flow_search_by_table(swft, om,
    5112           0 :             ntohs(ofm->fm_priority)))) {
    5113           0 :                 if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_CHECK_OVERLAP) {
    5114           0 :                         error = OFP_ERRFLOWMOD_OVERLAP;
    5115           0 :                         goto ofp_error;
    5116             :                 }
    5117             :         }
    5118             : 
    5119           0 :         if ((swfe = malloc(sizeof(*swfe), M_DEVBUF,
    5120           0 :             M_DONTWAIT|M_ZERO)) == NULL) {
    5121           0 :                 error = OFP_ERRFLOWMOD_UNKNOWN;
    5122           0 :                 goto ofp_error;
    5123             :         }
    5124             : 
    5125           0 :         swfe->swfe_priority = ntohs(ofm->fm_priority);
    5126           0 :         swfe->swfe_cookie =  be64toh(ofm->fm_cookie);
    5127           0 :         swfe->swfe_flags = ntohs(ofm->fm_flags);
    5128           0 :         swfe->swfe_idle_timeout = ntohs(ofm->fm_idle_timeout);
    5129           0 :         swfe->swfe_hard_timeout = ntohs(ofm->fm_hard_timeout);
    5130           0 :         nanouptime(&swfe->swfe_installed_time);
    5131           0 :         nanouptime(&swfe->swfe_idle_time);
    5132             : 
    5133           0 :         if ((swfe->swfe_match = malloc(omlen, M_DEVBUF,
    5134           0 :             M_DONTWAIT|M_ZERO)) == NULL) {
    5135           0 :                 error = OFP_ERRFLOWMOD_UNKNOWN;
    5136           0 :                 goto ofp_error_free_flow;
    5137             :         }
    5138           0 :         memcpy(swfe->swfe_match, om, omlen);
    5139             : 
    5140             :         /*
    5141             :          * If the ofp_match structure is empty and priority is zero, then
    5142             :          * this is a special flow type called table-miss which is the last
    5143             :          * flow to match.
    5144             :          */
    5145           0 :         if (omlen == sizeof(*om) && swfe->swfe_priority == 0)
    5146           0 :                 swfe->swfe_tablemiss = 1;
    5147             : 
    5148           0 :         if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype, &error))
    5149             :                 goto ofp_error_free_flow;
    5150             : 
    5151           0 :         if (old_swfe) {
    5152           0 :                 if (!(ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS)) {
    5153           0 :                         swfe->swfe_packet_cnt = old_swfe->swfe_packet_cnt;
    5154           0 :                         swfe->swfe_byte_cnt = old_swfe->swfe_byte_cnt;
    5155           0 :                 }
    5156             :                 /*
    5157             :                  * Doesn't need to send flow remove message because
    5158             :                  * this deleted flow cause by internal reason
    5159             :                  */
    5160           0 :                 swfe->swfe_flags &= ~(OFP_FLOWFLAG_SEND_FLOW_REMOVED);
    5161           0 :                 swofp_flow_entry_delete(sc, swft, old_swfe,
    5162             :                     OFP_FLOWREM_REASON_DELETE);
    5163           0 :         }
    5164             : 
    5165           0 :         swofp_flow_entry_add(sc, swft, swfe);
    5166             : 
    5167           0 :         m_freem(m);
    5168           0 :         return (0);
    5169             : 
    5170             :  ofp_error_free_flow:
    5171           0 :         swofp_flow_entry_free(&swfe);
    5172             :  ofp_error:
    5173           0 :         swofp_send_error(sc, m, etype, error);
    5174           0 :         return (0);
    5175           0 : }
    5176             : 
    5177             : int
    5178           0 : swofp_flow_mod_cmd_common_modify(struct switch_softc *sc, struct mbuf *m,
    5179             :     int strict)
    5180             : {
    5181             :         struct ofp_flow_mod             *ofm;
    5182             :         struct ofp_match                *om;
    5183             :         struct swofp_flow_entry         *swfe;
    5184             :         struct swofp_flow_table         *swft;
    5185             :         int                              omlen;
    5186           0 :         uint16_t                         error, etype;
    5187             : 
    5188           0 :         etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
    5189             : 
    5190           0 :         ofm = mtod(m, struct ofp_flow_mod *);
    5191           0 :         om = &ofm->fm_match;
    5192             : 
    5193           0 :         if (OFP_TABLE_ID_MAX < ofm->fm_table_id) {
    5194           0 :                 error = OFP_ERRFLOWMOD_TABLE_ID;
    5195           0 :                 goto ofp_error;
    5196             :         }
    5197             : 
    5198           0 :         if (ofm->fm_cookie == UINT64_MAX) {
    5199             :                 /* XXX What is best error code? */
    5200           0 :                 error = OFP_ERRFLOWMOD_UNKNOWN;
    5201           0 :                 goto ofp_error;
    5202             :         }
    5203             : 
    5204           0 :         omlen = ntohs(om->om_length);
    5205             :         /*
    5206             :          * 1) ofp_match header must have at least its own size,
    5207             :          *    otherwise memcpy() will fail later;
    5208             :          * 2) OXM filters can't be bigger than the packet.
    5209             :          */
    5210           0 :         if (omlen < sizeof(*om) ||
    5211           0 :             omlen >= (m->m_len - sizeof(*ofm))) {
    5212           0 :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5213           0 :                 error = OFP_ERRMATCH_BAD_LEN;
    5214           0 :                 goto ofp_error;
    5215             :         }
    5216             : 
    5217             :         /* Validate that the OXM are in-place and correct. */
    5218           0 :         if (swofp_validate_flow_match(om, &error)) {
    5219           0 :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5220           0 :                 goto ofp_error;
    5221             :         }
    5222             : 
    5223           0 :         if ((swft = swofp_flow_table_lookup(sc, ofm->fm_table_id)) == NULL) {
    5224           0 :                 error = OFP_ERRFLOWMOD_TABLE_ID;
    5225           0 :                 goto ofp_error;
    5226             :         }
    5227             : 
    5228           0 :         LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
    5229           0 :                 if (strict && !swofp_flow_cmp_strict(swfe, om,
    5230           0 :                     ntohs(ofm->fm_priority)))
    5231             :                         continue;
    5232           0 :                 else if (!swofp_flow_cmp_non_strict(swfe, om))
    5233             :                         continue;
    5234             : 
    5235           0 :                 if (!swofp_flow_filter(swfe, be64toh(ofm->fm_cookie),
    5236           0 :                     be64toh(ofm->fm_cookie_mask), ntohl(ofm->fm_out_port),
    5237           0 :                     ntohl(ofm->fm_out_group)))
    5238             :                         continue;
    5239             : 
    5240           0 :                 if (swofp_flow_entry_put_instructions(sc, m, swfe, &etype,
    5241             :                     &error)) {
    5242             :                         /*
    5243             :                          * If error occurs in swofp_flow_entry_put_instructions,
    5244             :                          * the flow entry might be half-way modified. So the
    5245             :                          * flow entry is delete here.
    5246             :                          */
    5247           0 :                         swofp_flow_entry_delete(sc, swft, swfe,
    5248             :                             OFP_FLOWREM_REASON_DELETE);
    5249           0 :                         etype = OFP_ERRTYPE_BAD_INSTRUCTION;
    5250           0 :                         goto ofp_error;
    5251             :                 }
    5252             : 
    5253           0 :                 if (ntohs(ofm->fm_flags) & OFP_FLOWFLAG_RESET_COUNTS) {
    5254           0 :                         swfe->swfe_packet_cnt = 0;
    5255           0 :                         swfe->swfe_byte_cnt = 0;
    5256           0 :                 }
    5257             :         }
    5258             : 
    5259           0 :         m_freem(m);
    5260           0 :         return (0);
    5261             : 
    5262             :  ofp_error:
    5263           0 :         swofp_send_error(sc, m, etype, error);
    5264           0 :         return (0);
    5265           0 : }
    5266             : 
    5267             : int
    5268           0 : swofp_flow_mod_cmd_modify(struct switch_softc *sc, struct mbuf *m)
    5269             : {
    5270           0 :         return swofp_flow_mod_cmd_common_modify(sc, m, 0);
    5271             : }
    5272             : 
    5273             : int
    5274           0 : swofp_flow_mod_cmd_modify_strict(struct switch_softc *sc, struct mbuf *m)
    5275             : {
    5276           0 :         return swofp_flow_mod_cmd_common_modify(sc, m, 1);
    5277             : }
    5278             : 
    5279             : 
    5280             : int
    5281           0 : swofp_flow_mod_cmd_common_delete(struct switch_softc *sc, struct mbuf *m,
    5282             :     int strict)
    5283             : {
    5284           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    5285             :         struct ofp_flow_mod     *ofm;
    5286             :         struct ofp_match        *om;
    5287             :         struct swofp_flow_table *swft;
    5288             :         int                      omlen;
    5289           0 :         uint16_t                 error, etype = OFP_ERRTYPE_FLOW_MOD_FAILED;
    5290             : 
    5291           0 :         ofm = (struct ofp_flow_mod *)(mtod(m, caddr_t));
    5292           0 :         om = &ofm->fm_match;
    5293             : 
    5294           0 :         omlen = ntohs(om->om_length);
    5295             :         /*
    5296             :          * 1) ofp_match header must have at least its own size,
    5297             :          *    otherwise memcpy() will fail later;
    5298             :          * 2) OXM filters can't be bigger than the packet.
    5299             :          */
    5300           0 :         if (omlen < sizeof(*om) ||
    5301           0 :             omlen >= (m->m_len - sizeof(*ofm))) {
    5302             :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5303           0 :                 error = OFP_ERRMATCH_BAD_LEN;
    5304           0 :                 goto ofp_error;
    5305             :         }
    5306             : 
    5307             :         /* Validate that the OXM are in-place and correct. */
    5308           0 :         if (swofp_validate_flow_match(om, &error)) {
    5309             :                 etype = OFP_ERRTYPE_BAD_MATCH;
    5310           0 :                 goto ofp_error;
    5311             :         }
    5312             : 
    5313           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    5314           0 :                 if ((ofm->fm_table_id != OFP_TABLE_ID_ALL) &&
    5315           0 :                     (ofm->fm_table_id != swft->swft_table_id))
    5316             :                         continue;
    5317             : 
    5318           0 :                 swofp_flow_delete_on_table(sc, swft, om,
    5319           0 :                     ntohs(ofm->fm_priority),
    5320           0 :                     be64toh(ofm->fm_cookie),
    5321           0 :                     be64toh(ofm->fm_cookie_mask),
    5322           0 :                     ntohl(ofm->fm_out_port),
    5323           0 :                     ntohl(ofm->fm_out_group), strict);
    5324           0 :         }
    5325             : 
    5326           0 :         m_freem(m);
    5327           0 :         return (0);
    5328             : 
    5329             :  ofp_error:
    5330           0 :         swofp_send_error(sc, m, etype, error);
    5331           0 :         return (-1);
    5332           0 : }
    5333             : 
    5334             : int
    5335           0 : swofp_flow_mod_cmd_delete(struct switch_softc *sc, struct mbuf *m)
    5336             : {
    5337           0 :         return swofp_flow_mod_cmd_common_delete(sc, m, 0);
    5338             : }
    5339             : 
    5340             : int
    5341           0 : swofp_flow_mod_cmd_delete_strict(struct switch_softc *sc, struct mbuf *m)
    5342             : {
    5343           0 :         return swofp_flow_mod_cmd_common_delete(sc, m, 1);
    5344             : }
    5345             : 
    5346             : ofp_msg_handler *
    5347           0 : swofp_flow_mod_lookup_handler(uint8_t cmd)
    5348             : {
    5349           0 :         if (cmd >= nitems(ofp_flow_mod_table))
    5350           0 :                 return (NULL);
    5351             :         else
    5352           0 :                 return (&ofp_flow_mod_table[cmd].ofm_cmd_handler);
    5353           0 : }
    5354             : 
    5355             : int
    5356           0 : swofp_flow_mod(struct switch_softc *sc, struct mbuf *m)
    5357             : {
    5358             :         struct ofp_flow_mod     *ofm;
    5359             :         ofp_msg_handler         *handler;
    5360             :         uint16_t                 ohlen;
    5361             : 
    5362           0 :         ofm = mtod(m, struct ofp_flow_mod *);
    5363           0 :         ohlen = ntohs(ofm->fm_oh.oh_length);
    5364           0 :         if (ohlen < sizeof(*ofm) ||
    5365           0 :             ohlen < (sizeof(*ofm) + ntohs(ofm->fm_match.om_length))) {
    5366           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5367             :                     OFP_ERRREQ_BAD_LEN);
    5368           0 :                 return (-1);
    5369             :         }
    5370             : 
    5371           0 :         handler = swofp_flow_mod_lookup_handler(ofm->fm_command);
    5372           0 :         if (handler) {
    5373           0 :                 (*handler)(sc, m);
    5374           0 :         } else {
    5375           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_FLOW_MOD_FAILED,
    5376             :                                  OFP_ERRFLOWMOD_BAD_COMMAND);
    5377             :         }
    5378             : 
    5379           0 :         return (0);
    5380           0 : }
    5381             : 
    5382             : int
    5383           0 : swofp_group_mod_add(struct switch_softc *sc, struct mbuf *m)
    5384             : {
    5385           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    5386             :         struct ofp_group_mod            *ogm;
    5387             :         struct swofp_group_entry        *swge;
    5388           0 :         uint16_t                         error, etype;
    5389             : 
    5390           0 :         etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
    5391           0 :         ogm = mtod(m, struct ofp_group_mod *);
    5392             : 
    5393           0 :         if (ofs->swofs_group_table_num >= ofs->swofs_group_max_table) {
    5394           0 :                 error = OFP_ERRGROUPMOD_OUT_OF_GROUPS;
    5395           0 :                 goto failed;
    5396             :         }
    5397             : 
    5398           0 :         if (ntohl(ogm->gm_group_id) > OFP_GROUP_ID_MAX) {
    5399           0 :                 error = OFP_ERRGROUPMOD_INVALID_GROUP;
    5400           0 :                 goto failed;
    5401             :         }
    5402             : 
    5403           0 :         if ((swge = swofp_group_entry_lookup(sc,
    5404             :             ntohl(ogm->gm_group_id)))) {
    5405           0 :                 error = OFP_ERRGROUPMOD_GROUP_EXISTS;
    5406           0 :                 goto failed;
    5407             :         }
    5408             : 
    5409           0 :         if (ogm->gm_type != OFP_GROUP_T_ALL) {
    5410             :                 /* support ALL group only now*/
    5411           0 :                 error = OFP_ERRGROUPMOD_BAD_TYPE;
    5412           0 :                 goto failed;
    5413             :         }
    5414             : 
    5415           0 :         if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error))
    5416             :                 goto failed;
    5417             : 
    5418           0 :         if ((swge = malloc(sizeof(*swge), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
    5419           0 :                 error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
    5420           0 :                 goto failed;
    5421             :         }
    5422             : 
    5423           0 :         swge->swge_group_id = ntohl(ogm->gm_group_id);
    5424           0 :         swge->swge_type = ogm->gm_type;
    5425             : 
    5426           0 :         swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) -
    5427             :             offsetof(struct ofp_group_mod, gm_buckets));
    5428             : 
    5429           0 :         if (swge->swge_buckets_len > 0) {
    5430           0 :                 if ((swge->swge_buckets = malloc(swge->swge_buckets_len,
    5431           0 :                     M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
    5432           0 :                         free(swge, M_DEVBUF, sizeof(*swge));
    5433           0 :                         error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
    5434           0 :                         goto failed;
    5435             :                 }
    5436             : 
    5437           0 :                 m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets),
    5438           0 :                     swge->swge_buckets_len, (caddr_t)swge->swge_buckets);
    5439           0 :         }
    5440             : 
    5441           0 :         swofp_group_entry_add(sc, swge);
    5442             : 
    5443           0 :         m_freem(m);
    5444           0 :         return (0);
    5445             : 
    5446             :  failed:
    5447           0 :         swofp_send_error(sc, m, etype, error);
    5448           0 :         return (0);
    5449           0 : }
    5450             : 
    5451             : int
    5452           0 : swofp_group_mod_modify(struct switch_softc *sc, struct mbuf *m)
    5453             : {
    5454             :         struct ofp_group_mod            *ogm;
    5455             :         struct swofp_group_entry        *swge;
    5456           0 :         uint16_t                         error, etype;
    5457             :         uint32_t                         obucketlen;
    5458             : 
    5459           0 :         etype = OFP_ERRTYPE_GROUP_MOD_FAILED;
    5460           0 :         ogm = mtod(m, struct ofp_group_mod *);
    5461             : 
    5462           0 :         if (ogm->gm_type != OFP_GROUP_T_ALL) {
    5463             :                 /* support ALL group only now */
    5464           0 :                 error = OFP_ERRGROUPMOD_BAD_TYPE;
    5465           0 :                 goto failed;
    5466             :         }
    5467             : 
    5468           0 :         if ((swge = swofp_group_entry_lookup(sc,
    5469           0 :             ntohl(ogm->gm_group_id))) == NULL) {
    5470           0 :                 error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
    5471           0 :                 goto failed;
    5472             :         }
    5473             : 
    5474           0 :         if (swofp_validate_buckets(sc, m, ogm->gm_type, &etype, &error))
    5475             :                 goto failed;
    5476             : 
    5477           0 :         swge->swge_type = ogm->gm_type;
    5478             : 
    5479           0 :         obucketlen = swge->swge_buckets_len;
    5480           0 :         swge->swge_buckets_len = (ntohs(ogm->gm_oh.oh_length) -
    5481             :             offsetof(struct ofp_group_mod, gm_buckets));
    5482             : 
    5483           0 :         if (obucketlen != swge->swge_buckets_len) {
    5484           0 :                 free(swge->swge_buckets, M_DEVBUF, obucketlen);
    5485           0 :                 swge->swge_buckets = NULL;
    5486             : 
    5487           0 :                 if (swge->swge_buckets_len > 0 &&
    5488           0 :                     (swge->swge_buckets = malloc(swge->swge_buckets_len,
    5489           0 :                     M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
    5490           0 :                         free(swge, M_DEVBUF, sizeof(*swge));
    5491           0 :                         error = OFP_ERRGROUPMOD_UNKNOWN_GROUP;
    5492           0 :                         goto failed;
    5493             :                 }
    5494             :         }
    5495             : 
    5496           0 :         if (swge->swge_buckets != NULL)
    5497           0 :                 m_copydata(m, offsetof(struct ofp_group_mod, gm_buckets),
    5498           0 :                     swge->swge_buckets_len, (caddr_t)swge->swge_buckets);
    5499             : 
    5500           0 :         m_freem(m);
    5501           0 :         return (0);
    5502             : failed:
    5503           0 :         swofp_send_error(sc, m, etype, error);
    5504           0 :         return (0);
    5505           0 : }
    5506             : 
    5507             : int
    5508           0 : swofp_group_mod_delete(struct switch_softc *sc, struct mbuf *m)
    5509             : {
    5510             :         struct ofp_group_mod            *ogm;
    5511             :         struct swofp_group_entry        *swge;
    5512             :         int                              group_id;
    5513             : 
    5514           0 :         ogm = mtod(m, struct ofp_group_mod *);
    5515           0 :         group_id = ntohl(ogm->gm_group_id);
    5516             : 
    5517           0 :         if (group_id == OFP_GROUP_ID_ALL)
    5518           0 :                 swofp_group_entry_delete_all(sc);
    5519           0 :         else if ((swge = swofp_group_entry_lookup(sc, group_id)) != NULL)
    5520           0 :                 swofp_group_entry_delete(sc, swge);
    5521             :         else {
    5522           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED,
    5523             :                     OFP_ERRGROUPMOD_UNKNOWN_GROUP);
    5524           0 :                 return (0);
    5525             :         }
    5526             : 
    5527           0 :         m_freem(m);
    5528           0 :         return (0);
    5529           0 : }
    5530             : 
    5531             : int
    5532           0 : swofp_group_mod(struct switch_softc *sc, struct mbuf *m)
    5533             : {
    5534             :         struct ofp_group_mod    *ogm;
    5535             :         uint16_t                 cmd;
    5536             : 
    5537           0 :         ogm = mtod(m, struct ofp_group_mod *);
    5538           0 :         if (ntohs(ogm->gm_oh.oh_length) < sizeof(*ogm)) {
    5539           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5540             :                     OFP_ERRREQ_BAD_LEN);
    5541           0 :                 return (-1);
    5542             :         }
    5543             : 
    5544           0 :         cmd = ntohs(ogm->gm_command);
    5545             : 
    5546           0 :         switch (cmd) {
    5547             :         case OFP_GROUPCMD_ADD:
    5548           0 :                 return swofp_group_mod_add(sc, m);
    5549             :         case OFP_GROUPCMD_MODIFY:
    5550           0 :                 return swofp_group_mod_modify(sc, m);
    5551             :         case OFP_GROUPCMD_DELETE:
    5552           0 :                 return swofp_group_mod_delete(sc, m);
    5553             :         default:
    5554           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_GROUP_MOD_FAILED,
    5555             :                     OFP_ERRGROUPMOD_BAD_COMMAND);
    5556             :                 break;
    5557             :         }
    5558             : 
    5559           0 :         return (0);
    5560           0 : }
    5561             : 
    5562             : 
    5563             : 
    5564             : /*
    5565             :  * OpenFlow protocol PACKET OUT message handler
    5566             :  */
    5567             : int
    5568           0 : swofp_recv_packet_out(struct switch_softc *sc, struct mbuf *m)
    5569             : {
    5570             :         struct ofp_packet_out           *pout;
    5571             :         struct ofp_action_header        *ah;
    5572             :         struct mbuf                     *mc = NULL, *mcn;
    5573             :         int                              al_start, al_len, off;
    5574           0 :         uint16_t                         ohlen, error;
    5575           0 :         struct switch_flow_classify      swfcl = {};
    5576           0 :         struct swofp_pipeline_desc       swpld = { .swpld_swfcl = &swfcl };
    5577             : 
    5578           0 :         pout = mtod(m, struct ofp_packet_out *);
    5579           0 :         ohlen = ntohs(pout->pout_oh.oh_length);
    5580           0 :         if (ohlen < sizeof(*pout) ||
    5581           0 :             ohlen < (sizeof(*pout) + ntohs(pout->pout_actions_len))) {
    5582           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5583             :                     OFP_ERRREQ_BAD_LEN);
    5584           0 :                 return (-1);
    5585             :         }
    5586             : 
    5587             :         al_len = ntohs(pout->pout_actions_len);
    5588             :         al_start = offsetof(struct ofp_packet_out, pout_actions);
    5589             : 
    5590             :        /* Validate actions before anything else. */
    5591           0 :         ah = (struct ofp_action_header *)
    5592           0 :             ((uint8_t *)pout + sizeof(*pout));
    5593           0 :         if (swofp_validate_action(sc, ah, al_len, &error)) {
    5594           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_ACTION, error);
    5595           0 :                 return (EINVAL);
    5596             :         }
    5597             : 
    5598           0 :         if (pout->pout_buffer_id == OFP_PKTOUT_NO_BUFFER) {
    5599             :                 /*
    5600             :                  * It's not necessary to deep copy at here because it's done
    5601             :                  * in m_dup_pkt().
    5602             :                  */
    5603           0 :                 if ((mc = m_split(m, (al_start + al_len), M_NOWAIT)) == NULL) {
    5604           0 :                         m_freem(m);
    5605           0 :                         return (ENOBUFS);
    5606             :                 }
    5607             : 
    5608           0 :                 mcn = m_dup_pkt(mc, ETHER_ALIGN, M_NOWAIT);
    5609           0 :                 m_freem(mc);
    5610           0 :                 if (mcn == NULL) {
    5611           0 :                         m_freem(m);
    5612           0 :                         return (ENOBUFS);
    5613             :                 }
    5614             : 
    5615             :                 mc = mcn;
    5616             :         } else {
    5617             :                 /* TODO We don't do buffering yet. */
    5618           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5619             :                     OFP_ERRREQ_BUFFER_UNKNOWN);
    5620           0 :                 return (0);
    5621             :         }
    5622             : 
    5623           0 :         mc = switch_flow_classifier(mc, pout->pout_in_port, &swfcl);
    5624           0 :         if (mc == NULL) {
    5625           0 :                 m_freem(m);
    5626           0 :                 return (0);
    5627             :         }
    5628             : 
    5629           0 :         TAILQ_INIT(&swpld.swpld_fwdp_q);
    5630           0 :         swfcl.swfcl_in_port = ntohl(pout->pout_in_port);
    5631           0 :         for (off = al_start; off < al_start + al_len;
    5632           0 :             off += ntohs(ah->ah_len)) {
    5633           0 :                 ah = (struct ofp_action_header *)(mtod(m, caddr_t) + off);
    5634             : 
    5635           0 :                 mc = swofp_execute_action(sc, mc, &swpld, ah);
    5636           0 :                 if (mc == NULL)
    5637             :                         break;
    5638             :         }
    5639             : 
    5640           0 :         if (mc)
    5641           0 :                 switch_port_egress(sc, &swpld.swpld_fwdp_q, mc);
    5642             : 
    5643           0 :         m_freem(m);
    5644             : 
    5645           0 :         return (0);
    5646           0 : }
    5647             : 
    5648             : /*
    5649             :  * OpenFlow protocol MULTIPART message:
    5650             :  *
    5651             :  *  Multipart messages are used to carry a large amount of data because a single
    5652             :  *  OpenFlow message is limited to 64KB. If a message is over 64KB, it is
    5653             :  *  splited some OpenFlow messages. OpenFlow Switch Specification says that
    5654             :  *  "NO OBJECT CAN BE SPLIT ACROSS TWO MESSAGES". In other words, point of
    5655             :  *  splittig is different per reply, so switch(4) builds multipart message using
    5656             :  *  swofp_mpms_* functions which splits messsages not to object across
    5657             :  *  two messages.
    5658             :  */
    5659             : int
    5660           0 : swofp_mpmsg_reply_create(struct ofp_multipart *req, struct swofp_mpmsg *swmp)
    5661             : {
    5662             :         struct mbuf             *hdr, *body;
    5663             :         struct ofp_multipart    *omp;
    5664             : 
    5665           0 :         memset(swmp, 0, sizeof(*swmp));
    5666             : 
    5667           0 :         ml_init(&swmp->swmp_body);
    5668             : 
    5669           0 :         MGETHDR(hdr, M_DONTWAIT, MT_DATA);
    5670           0 :         if (hdr == NULL)
    5671             :                 goto error;
    5672             : 
    5673           0 :         memset(mtod(hdr, caddr_t), 0, sizeof(*omp));
    5674           0 :         omp = mtod(hdr, struct ofp_multipart *);
    5675           0 :         omp->mp_oh.oh_version = req->mp_oh.oh_version;
    5676           0 :         omp->mp_oh.oh_xid = req->mp_oh.oh_xid;
    5677           0 :         omp->mp_oh.oh_type = OFP_T_MULTIPART_REPLY;
    5678           0 :         omp->mp_type = req->mp_type;
    5679           0 :         hdr->m_len = hdr->m_pkthdr.len = sizeof(*omp);
    5680           0 :         swmp->swmp_hdr = hdr;
    5681             : 
    5682           0 :         MGETHDR(body, M_DONTWAIT, MT_DATA);
    5683           0 :         if (body == NULL)
    5684             :                 goto error;
    5685           0 :         MCLGET(body, M_DONTWAIT);
    5686           0 :         if ((body->m_flags & M_EXT) == 0) {
    5687           0 :                 m_freem(body);
    5688           0 :                 goto error;
    5689             :         }
    5690           0 :         body->m_len = body->m_pkthdr.len = 0;
    5691             : 
    5692           0 :         ml_enqueue(&swmp->swmp_body, body);
    5693             : 
    5694           0 :         return (0);
    5695             : 
    5696             :  error:
    5697           0 :         m_freem(hdr);
    5698           0 :         swmp->swmp_hdr = NULL;
    5699           0 :         return (ENOBUFS);
    5700           0 : }
    5701             : 
    5702             : /*
    5703             :  * Copy data from a buffer back into the indicated swmp's body buffer
    5704             :  */
    5705             : int
    5706           0 : swofp_mpmsg_put(struct swofp_mpmsg *swmp, caddr_t data, size_t len)
    5707             : {
    5708             :         struct mbuf     *m, *n;
    5709             :         int              error;
    5710             : 
    5711           0 :         KASSERT(swmp->swmp_hdr != NULL);
    5712             : 
    5713           0 :         m = swmp->swmp_body.ml_tail;
    5714           0 :         if (m == NULL)
    5715           0 :                 return (ENOBUFS);
    5716             : 
    5717           0 :         if (m->m_pkthdr.len + len > SWOFP_MPMSG_MAX) {
    5718           0 :                 MGETHDR(n, M_DONTWAIT, MT_DATA);
    5719           0 :                 if (n == NULL)
    5720           0 :                         return (ENOBUFS);
    5721           0 :                 MCLGET(n, M_DONTWAIT);
    5722           0 :                 if ((n->m_flags & M_EXT) == 0) {
    5723           0 :                         m_freem(n);
    5724           0 :                         return (ENOBUFS);
    5725             :                 }
    5726           0 :                 n->m_len = n->m_pkthdr.len = 0;
    5727             : 
    5728           0 :                 ml_enqueue(&swmp->swmp_body, n);
    5729             : 
    5730             :                 m = n;
    5731           0 :         }
    5732             : 
    5733           0 :         if ((error = m_copyback(m, m->m_pkthdr.len, len, data, M_NOWAIT)))
    5734           0 :                 return (error);
    5735             : 
    5736           0 :         return (0);
    5737           0 : }
    5738             : 
    5739             : /*
    5740             :  * Copy data from a mbuf back into the indicated swmp's body buffer
    5741             :  */
    5742             : int
    5743           0 : swofp_mpmsg_m_put(struct swofp_mpmsg *swmp, struct mbuf *msg)
    5744             : {
    5745             :         struct mbuf     *m, *n;
    5746             :         int              len;
    5747             : 
    5748           0 :         KASSERT(swmp->swmp_hdr != NULL);
    5749             : 
    5750           0 :         m = swmp->swmp_body.ml_tail;
    5751           0 :         if (m == NULL)
    5752           0 :                 return (ENOBUFS);
    5753             : 
    5754           0 :         if (m->m_pkthdr.len + msg->m_pkthdr.len > SWOFP_MPMSG_MAX) {
    5755           0 :                 MGETHDR(n, M_DONTWAIT, MT_DATA);
    5756           0 :                 if (n == NULL)
    5757           0 :                         return (ENOBUFS);
    5758           0 :                 MCLGET(n, M_DONTWAIT);
    5759           0 :                 if ((n->m_flags & M_EXT) == 0) {
    5760           0 :                         m_freem(n);
    5761           0 :                         return (ENOBUFS);
    5762             :                 }
    5763           0 :                 n->m_len = n->m_pkthdr.len = 0;
    5764             : 
    5765           0 :                 ml_enqueue(&swmp->swmp_body, n);
    5766             : 
    5767             :                 m = n;
    5768           0 :         }
    5769             : 
    5770           0 :         len = m->m_pkthdr.len + msg->m_pkthdr.len;
    5771           0 :         m_cat(m, msg);
    5772           0 :         m->m_pkthdr.len = len;
    5773             : 
    5774           0 :         return (0);
    5775           0 : }
    5776             : 
    5777             : void
    5778           0 : swofp_mpmsg_destroy(struct swofp_mpmsg *swmp)
    5779             : {
    5780           0 :         m_freem(swmp->swmp_hdr);
    5781           0 :         ml_purge(&swmp->swmp_body);
    5782           0 : }
    5783             : 
    5784             : int
    5785           0 : swofp_multipart_req(struct switch_softc *sc, struct mbuf *m)
    5786             : {
    5787             :         struct ofp_multipart    *omp;
    5788             :         ofp_msg_handler          handler;
    5789             : 
    5790           0 :         omp = mtod(m, struct ofp_multipart *);
    5791           0 :         if (ntohs(omp->mp_oh.oh_length) < sizeof(*omp)) {
    5792           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5793             :                     OFP_ERRREQ_BAD_LEN);
    5794           0 :                 return (-1);
    5795             :         }
    5796             : 
    5797           0 :         if (omp->mp_flags & OFP_T_MULTIPART_REQUEST) {
    5798             :                 /* multipart message re-assembly iss not supported yet */
    5799           0 :                 m_freem(m);
    5800           0 :                 return (ENOBUFS);
    5801             :         }
    5802             : 
    5803           0 :         handler = swofp_lookup_mpmsg_handler(ntohs(omp->mp_type));
    5804           0 :         if (handler)
    5805           0 :                 (*handler)(sc, m);
    5806             :         else
    5807           0 :                 swofp_send_error(sc, m, OFP_ERRTYPE_BAD_REQUEST,
    5808             :                     OFP_ERRREQ_MULTIPART);
    5809             : 
    5810           0 :         return (0);
    5811           0 : }
    5812             : 
    5813             : int
    5814           0 : swofp_multipart_reply(struct switch_softc *sc, struct swofp_mpmsg *swmp)
    5815             : {
    5816             :         struct ofp_multipart    *omp;
    5817             :         struct mbuf             *hdr, *body;
    5818             :         int                      len, error = 0;
    5819             : 
    5820           0 :         KASSERT(swmp->swmp_hdr != NULL);
    5821             : 
    5822           0 :         omp = mtod(swmp->swmp_hdr, struct ofp_multipart *);
    5823             : 
    5824           0 :         while ((body = ml_dequeue(&swmp->swmp_body)) != NULL) {
    5825           0 :                 omp->mp_oh.oh_length = htons(sizeof(*omp) + body->m_pkthdr.len);
    5826             : 
    5827           0 :                 if (swmp->swmp_body.ml_tail != NULL) {
    5828           0 :                         omp->mp_flags |= htons(OFP_MP_FLAG_REPLY_MORE);
    5829           0 :                         if ((hdr = m_dup_pkt(swmp->swmp_hdr, 0,
    5830           0 :                             M_WAITOK)) == NULL) {
    5831             :                                 error = ENOBUFS;
    5832             :                                 goto error;
    5833             :                         }
    5834             :                 } else {
    5835           0 :                         omp->mp_flags &= ~htons(OFP_MP_FLAG_REPLY_MORE);
    5836           0 :                         hdr = swmp->swmp_hdr;
    5837             :                 }
    5838             : 
    5839           0 :                 if (body->m_pkthdr.len) {
    5840           0 :                         len = hdr->m_pkthdr.len + body->m_pkthdr.len;
    5841           0 :                         m_cat(hdr, body);
    5842           0 :                         hdr->m_pkthdr.len = len;
    5843           0 :                 } else
    5844           0 :                         m_freem(body);
    5845             : 
    5846           0 :                 (void)swofp_output(sc, hdr);
    5847             :         }
    5848             : 
    5849           0 :         return (0);
    5850             :  error:
    5851           0 :         swofp_mpmsg_destroy(swmp);
    5852           0 :         return (error);
    5853           0 : }
    5854             : 
    5855             : int
    5856           0 : swofp_put_flow(struct mbuf *m, struct swofp_flow_table *swft,
    5857             :     struct swofp_flow_entry *swfe)
    5858             : {
    5859           0 :         struct ofp_flow_stats   *pofs, ofs;
    5860           0 :         struct timespec          now, duration;
    5861             :         const uint8_t            pad_data[OFP_ALIGNMENT] = {};
    5862             :         struct mbuf             *n;
    5863           0 :         int                      start, off, error, offp, pad = 0;
    5864             :         int                      omlen;
    5865             : 
    5866           0 :         memset(&ofs, 0, sizeof(ofs));
    5867             : 
    5868           0 :         ofs.fs_table_id = swft->swft_table_id;
    5869           0 :         nanouptime(&now);
    5870           0 :         timespecsub(&now, &swfe->swfe_installed_time, &duration);
    5871           0 :         ofs.fs_duration_sec = ntohl((int)duration.tv_sec);
    5872           0 :         ofs.fs_priority = htons(swfe->swfe_priority);
    5873           0 :         ofs.fs_idle_timeout = htons(swfe->swfe_idle_timeout);
    5874           0 :         ofs.fs_hard_timeout = htons(swfe->swfe_hard_timeout);
    5875           0 :         ofs.fs_cookie = htobe64(swfe->swfe_cookie);
    5876           0 :         ofs.fs_byte_count = htobe64(swfe->swfe_byte_cnt);
    5877           0 :         ofs.fs_packet_count = htobe64(swfe->swfe_packet_cnt);
    5878             : 
    5879             :         /*
    5880             :          * struct ofp_flow_statsu has some fields which is variable length ,
    5881             :          * so the length is determined by all fields puts.
    5882             :          */
    5883           0 :         start = off = m->m_pkthdr.len;
    5884             : 
    5885             :         /*
    5886             :          * Put ofp_flow_stat exclusive ofp_match because ofp_match is put
    5887             :          * with ofp_matches
    5888             :          */
    5889           0 :         if ((error = m_copyback(m, off, (sizeof(ofs) -
    5890             :             sizeof(struct ofp_match)), &ofs, M_NOWAIT)))
    5891             :                 goto failed;
    5892           0 :         off += (sizeof(ofs) - sizeof(struct ofp_match));
    5893             : 
    5894             :         /*
    5895             :          * Put ofp_match include ofp_ox_matches and pad
    5896             :          */
    5897           0 :         omlen = ntohs(swfe->swfe_match->om_length);
    5898           0 :         pad = OFP_ALIGN(omlen) - omlen;
    5899           0 :         if ((error = m_copyback(m, off, omlen, swfe->swfe_match, M_NOWAIT)))
    5900             :                 goto failed;
    5901           0 :         off += omlen;
    5902           0 :         if ((error = m_copyback(m, off, pad, pad_data, M_NOWAIT)))
    5903             :                 goto failed;
    5904           0 :         off += pad;
    5905             : 
    5906             :         /*
    5907             :          * Put instructions
    5908             :          */
    5909           0 :         if (swfe->swfe_goto_table) {
    5910           0 :                 if ((error = m_copyback(m, off,
    5911           0 :                     ntohs(swfe->swfe_goto_table->igt_len),
    5912           0 :                     swfe->swfe_goto_table, M_NOWAIT)))
    5913             :                         goto failed;
    5914           0 :                 off += ntohs(swfe->swfe_goto_table->igt_len);
    5915           0 :         }
    5916           0 :         if (swfe->swfe_write_metadata) {
    5917           0 :                 if ((error = m_copyback(m, off,
    5918           0 :                     ntohs(swfe->swfe_write_metadata->iwm_len),
    5919           0 :                     swfe->swfe_write_metadata, M_NOWAIT)))
    5920             :                         goto failed;
    5921           0 :                 off += ntohs(swfe->swfe_write_metadata->iwm_len);
    5922           0 :         }
    5923           0 :         if (swfe->swfe_apply_actions) {
    5924           0 :                 if ((error = m_copyback(m, off,
    5925           0 :                     ntohs(swfe->swfe_apply_actions->ia_len),
    5926           0 :                     swfe->swfe_apply_actions, M_NOWAIT)))
    5927             :                         goto failed;
    5928           0 :                 off += ntohs(swfe->swfe_apply_actions->ia_len);
    5929           0 :         }
    5930           0 :         if (swfe->swfe_write_actions) {
    5931           0 :                 if ((error = m_copyback(m, off,
    5932           0 :                     ntohs(swfe->swfe_write_actions->ia_len),
    5933           0 :                     swfe->swfe_write_actions, M_NOWAIT)))
    5934             :                         goto failed;
    5935           0 :                 off += ntohs(swfe->swfe_write_actions->ia_len);
    5936           0 :         }
    5937           0 :         if (swfe->swfe_clear_actions) {
    5938           0 :                 if ((error = m_copyback(m, off,
    5939           0 :                     ntohs(swfe->swfe_clear_actions->ia_len),
    5940           0 :                     swfe->swfe_clear_actions, M_NOWAIT)))
    5941             :                         goto failed;
    5942           0 :                 off += ntohs(swfe->swfe_clear_actions->ia_len);
    5943           0 :         }
    5944             : 
    5945             :         /*
    5946             :          * Set ofp_flow_stat length
    5947             :          */
    5948           0 :         if ((n = m_pulldown(m, start, sizeof(*pofs), &offp)) == NULL)
    5949           0 :                 return (ENOBUFS);
    5950           0 :         pofs = (struct ofp_flow_stats *)(mtod(n, caddr_t) + offp);
    5951           0 :         pofs->fs_length = htons(off - start);
    5952             : 
    5953           0 :         return (0);
    5954             : 
    5955             :  failed:
    5956           0 :         m_freem(m);
    5957           0 :         return (error);
    5958           0 : }
    5959             : 
    5960             : int
    5961           0 : swofp_mp_recv_desc(struct switch_softc *sc, struct mbuf *m)
    5962             : {
    5963           0 :         struct ofp_desc          od;
    5964           0 :         struct swofp_mpmsg       swmp;
    5965             :         int                      error;
    5966             : 
    5967           0 :         if ((error = swofp_mpmsg_reply_create(
    5968           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    5969             :                 goto failed;
    5970             : 
    5971           0 :         memset(&od, 0, sizeof(od));
    5972             : 
    5973           0 :         strlcpy(od.d_mfr_desc, "openbsd.org", OFP_DESC_STR_LEN);
    5974           0 :         strlcpy(od.d_hw_desc, "openbsd", OFP_DESC_STR_LEN);
    5975           0 :         strlcpy(od.d_sw_desc, "openbsd", OFP_DESC_STR_LEN);
    5976           0 :         strlcpy(od.d_serial_num, "0", OFP_SERIAL_NUM_LEN);
    5977           0 :         strlcpy(od.d_dp_desc, sc->sc_if.if_xname, OFP_DESC_STR_LEN);
    5978             : 
    5979           0 :         if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&od, sizeof(od))))
    5980             :                 goto failed;
    5981             : 
    5982           0 :         m_freem(m);
    5983           0 :         return swofp_multipart_reply(sc, &swmp);
    5984             : 
    5985             :  failed:
    5986           0 :         m_freem(m);
    5987           0 :         swofp_mpmsg_destroy(&swmp);
    5988           0 :         return (error);
    5989           0 : }
    5990             : 
    5991             : int
    5992           0 : swofp_put_flows_from_table(struct swofp_mpmsg *swmp,
    5993             :     struct swofp_flow_table *swft, struct ofp_flow_stats_request *ofsr)
    5994             : {
    5995             :         struct swofp_flow_entry *swfe;
    5996             :         struct mbuf             *m;
    5997             :         int                      error = 0;
    5998             : 
    5999           0 :         LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
    6000           0 :                 if (!swofp_flow_cmp_non_strict(swfe, &ofsr->fsr_match))
    6001             :                         continue;
    6002             : 
    6003           0 :                 if (!swofp_flow_filter(swfe, be64toh(ofsr->fsr_cookie),
    6004           0 :                     be64toh(ofsr->fsr_cookie_mask), ntohl(ofsr->fsr_out_port),
    6005           0 :                     ntohl(ofsr->fsr_out_group)))
    6006             :                         continue;
    6007             : 
    6008           0 :                 MGETHDR(m, M_DONTWAIT, MT_DATA);
    6009           0 :                 if (m == NULL)
    6010           0 :                         return (ENOBUFS);
    6011           0 :                 m->m_len = m->m_pkthdr.len = 0;
    6012             : 
    6013           0 :                 if ((error = swofp_put_flow(m, swft, swfe)))
    6014             :                         break;
    6015             : 
    6016           0 :                 if ((error = swofp_mpmsg_m_put(swmp, m))) {
    6017             :                         /* swofp_mpmsg_m_put() doesn't free m on error */
    6018           0 :                         m_freem(m);
    6019           0 :                         break;
    6020             :                 }
    6021             :         }
    6022             : 
    6023           0 :         return (error);
    6024           0 : }
    6025             : 
    6026             : int
    6027           0 : swofp_mp_recv_flow(struct switch_softc *sc, struct mbuf *m)
    6028             : {
    6029           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    6030             :         struct ofp_flow_stats_request   *ofsr;
    6031             :         struct swofp_flow_table         *swft;
    6032           0 :         struct swofp_mpmsg               swmp;
    6033             :         int                              error;
    6034             : 
    6035           0 :         if ((error = swofp_mpmsg_reply_create(
    6036           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6037             :                 goto failed;
    6038             : 
    6039           0 :         ofsr = (struct ofp_flow_stats_request *)
    6040           0 :             (mtod(m, caddr_t) + sizeof(struct ofp_multipart));
    6041             : 
    6042           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    6043           0 :                 if ((ofsr->fsr_table_id != OFP_TABLE_ID_ALL) &&
    6044           0 :                     (ofsr->fsr_table_id != swft->swft_table_id))
    6045             :                         continue;
    6046             : 
    6047           0 :                 if ((error = swofp_put_flows_from_table(&swmp, swft, ofsr)))
    6048             :                         goto failed;
    6049             :         }
    6050             : 
    6051           0 :         m_freem(m);
    6052           0 :         return swofp_multipart_reply(sc, &swmp);
    6053             : 
    6054             :  failed:
    6055           0 :         m_freem(m);
    6056           0 :         swofp_mpmsg_destroy(&swmp);
    6057           0 :         return (error);
    6058           0 : }
    6059             : 
    6060             : void
    6061           0 : swofp_aggregate_stat_from_table(struct ofp_aggregate_stats *aggstat,
    6062             :     struct swofp_flow_table *swft, struct ofp_aggregate_stats_request *oasr)
    6063             : {
    6064             :         struct swofp_flow_entry *swfe;
    6065             :         uint64_t                 packet_cnt = 0, byte_cnt = 0;
    6066             :         uint32_t                 flow_cnt = 0;
    6067             : 
    6068           0 :         LIST_FOREACH(swfe, &swft->swft_flow_list, swfe_next) {
    6069           0 :                 if (!swofp_flow_cmp_non_strict(swfe, &oasr->asr_match))
    6070             :                         continue;
    6071             : 
    6072           0 :                 if (!swofp_flow_filter(swfe, be64toh(oasr->asr_cookie),
    6073           0 :                     be64toh(oasr->asr_cookie_mask), ntohl(oasr->asr_out_port),
    6074           0 :                     ntohl(oasr->asr_out_group)))
    6075             :                         continue;
    6076             : 
    6077           0 :                 packet_cnt += swfe->swfe_packet_cnt;
    6078           0 :                 byte_cnt += swfe->swfe_byte_cnt;
    6079           0 :                 flow_cnt++;
    6080           0 :         }
    6081             : 
    6082           0 :         aggstat->as_packet_count = htobe64(packet_cnt);
    6083           0 :         aggstat->as_byte_count = htobe64(byte_cnt);
    6084           0 :         aggstat->as_flow_count = htonl(flow_cnt++);
    6085           0 : }
    6086             : 
    6087             : int
    6088           0 : swofp_mp_recv_aggregate_flow_stat(struct switch_softc *sc, struct mbuf *m)
    6089             : {
    6090           0 :         struct swofp_ofs                        *ofs = sc->sc_ofs;
    6091             :         struct ofp_aggregate_stats_request      *oasr;
    6092             :         struct swofp_flow_table                 *swft;
    6093           0 :         struct swofp_mpmsg                       swmp;
    6094           0 :         struct ofp_aggregate_stats               aggstat;
    6095             :         int                                      error;
    6096             : 
    6097           0 :         if ((error = swofp_mpmsg_reply_create(
    6098           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6099             :                 goto failed;
    6100             : 
    6101           0 :         memset(&aggstat, 0, sizeof(aggstat));
    6102             : 
    6103           0 :         oasr = (struct ofp_aggregate_stats_request *)
    6104           0 :             (mtod(m, caddr_t) + sizeof(struct ofp_multipart));
    6105             : 
    6106           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    6107           0 :                 if ((oasr->asr_table_id != OFP_TABLE_ID_ALL) &&
    6108           0 :                     (oasr->asr_table_id != swft->swft_table_id))
    6109             :                         continue;
    6110           0 :                 swofp_aggregate_stat_from_table(&aggstat, swft, oasr);
    6111           0 :         }
    6112             : 
    6113           0 :         if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&aggstat,
    6114             :             sizeof(aggstat))))
    6115             :                 goto failed;
    6116             : 
    6117           0 :         m_freem(m);
    6118           0 :         return swofp_multipart_reply(sc, &swmp);
    6119             : 
    6120             :  failed:
    6121           0 :         m_freem(m);
    6122           0 :         swofp_mpmsg_destroy(&swmp);
    6123           0 :         return (error);
    6124           0 : }
    6125             : 
    6126             : int
    6127           0 : swofp_mp_recv_table_stats(struct switch_softc *sc, struct mbuf *m)
    6128             : {
    6129           0 :         struct swofp_ofs        *ofs = sc->sc_ofs;
    6130           0 :         struct ofp_table_stats   tblstat;
    6131             :         struct swofp_flow_table *swft;
    6132           0 :         struct swofp_mpmsg       swmp;
    6133             :         int                      error;
    6134             : 
    6135             : 
    6136           0 :         if ((error = swofp_mpmsg_reply_create(
    6137           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6138             :                 goto failed;
    6139             : 
    6140           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    6141           0 :                 memset(&tblstat, 0, sizeof(tblstat));
    6142             : 
    6143           0 :                 tblstat.ts_table_id = swft->swft_table_id;
    6144           0 :                 tblstat.ts_active_count = htonl((uint32_t)swft->swft_flow_num);
    6145           0 :                 tblstat.ts_lookup_count = htobe64(swft->swft_lookup_count);
    6146           0 :                 tblstat.ts_matched_count = htobe64(swft->swft_matched_count);
    6147             : 
    6148           0 :                 if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&tblstat,
    6149             :                     sizeof(tblstat))))
    6150             :                         goto failed;
    6151             :         }
    6152             : 
    6153           0 :         m_freem(m);
    6154           0 :         return swofp_multipart_reply(sc, &swmp);
    6155             : 
    6156             :  failed:
    6157           0 :         m_freem(m);
    6158           0 :         swofp_mpmsg_destroy(&swmp);
    6159           0 :         return (error);
    6160           0 : }
    6161             : 
    6162             : int
    6163           0 : swofp_mp_recv_port_stats(struct switch_softc *sc, struct mbuf *m)
    6164             : {
    6165             :         struct switch_port      *swpo;
    6166           0 :         struct swofp_mpmsg       swmp;
    6167             :         struct ifnet            *ifs;
    6168           0 :         struct ofp_port_stats    postat;
    6169             :         int                      error;
    6170           0 :         struct timespec          now, duration;
    6171             : 
    6172           0 :         if ((error = swofp_mpmsg_reply_create(
    6173           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6174             :                 goto failed;
    6175             : 
    6176           0 :         nanouptime(&now);
    6177             : 
    6178           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    6179           0 :                 memset(&postat, 0, sizeof(postat));
    6180           0 :                 ifs = if_get(swpo->swpo_ifindex);
    6181           0 :                 if (ifs == NULL)
    6182             :                         continue;
    6183             : 
    6184           0 :                 if (swpo->swpo_flags & IFBIF_LOCAL)
    6185           0 :                         postat.pt_port_no = htonl(OFP_PORT_LOCAL);
    6186             :                 else
    6187           0 :                         postat.pt_port_no = htonl(swpo->swpo_port_no);
    6188           0 :                 postat.pt_rx_packets = htobe64(ifs->if_ipackets);
    6189           0 :                 postat.pt_tx_packets = htobe64(ifs->if_opackets);
    6190           0 :                 postat.pt_rx_bytes = htobe64(ifs->if_obytes);
    6191           0 :                 postat.pt_tx_bytes = htobe64(ifs->if_ibytes);
    6192           0 :                 postat.pt_rx_dropped = htobe64(ifs->if_iqdrops);
    6193           0 :                 postat.pt_tx_dropped = htobe64(ifs->if_oqdrops);
    6194           0 :                 postat.pt_rx_errors = htobe64(ifs->if_ierrors);
    6195           0 :                 postat.pt_tx_errors = htobe64(ifs->if_oerrors);
    6196           0 :                 postat.pt_rx_frame_err = htobe64(0);
    6197           0 :                 postat.pt_rx_over_err = htobe64(0);
    6198           0 :                 postat.pt_rx_crc_err = htobe64(0);
    6199           0 :                 postat.pt_collision = htobe64(ifs->if_collisions);
    6200           0 :                 timespecsub(&now, &swpo->swpo_appended, &duration);
    6201           0 :                 postat.pt_duration_sec = htonl((uint32_t)duration.tv_sec);
    6202           0 :                 postat.pt_duration_nsec = htonl(duration.tv_nsec);
    6203             : 
    6204           0 :                 if_put(ifs);
    6205             : 
    6206           0 :                 if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&postat,
    6207             :                     sizeof(postat))))
    6208             :                         goto failed;
    6209             :         }
    6210             : 
    6211           0 :         m_freem(m);
    6212           0 :         return swofp_multipart_reply(sc, &swmp);
    6213             : 
    6214             :  failed:
    6215           0 :         m_freem(m);
    6216           0 :         swofp_mpmsg_destroy(&swmp);
    6217           0 :         return (error);
    6218           0 : }
    6219             : 
    6220             : int
    6221           0 : swofp_table_features_put_oxm(struct mbuf *m, int *off, uint16_t tp_type)
    6222             : {
    6223           0 :         struct ofp_table_feature_property        tp;
    6224           0 :         struct ofp_ox_match                      oxm;
    6225           0 :         uint32_t                                 padding = 0;
    6226             :         int                                      i, supported = 0;
    6227             : 
    6228           0 :         for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) {
    6229           0 :                 switch (tp_type) {
    6230             :                 case OFP_TABLE_FEATPROP_MATCH:
    6231           0 :                         if (ofp_oxm_handlers[i].oxm_match == NULL)
    6232             :                                 continue;
    6233             :                         break;
    6234             :                 case OFP_TABLE_FEATPROP_WILDCARDS:
    6235           0 :                         if (ofp_oxm_handlers[i].oxm_match == NULL ||
    6236           0 :                             !(ofp_oxm_handlers[i].oxm_flags &
    6237             :                             SWOFP_MATCH_WILDCARD))
    6238             :                                 continue;
    6239             :                         break;
    6240             :                 case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
    6241             :                 case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
    6242             :                 case OFP_TABLE_FEATPROP_WRITE_SETFIELD:
    6243             :                 case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
    6244           0 :                         if (ofp_oxm_handlers[i].oxm_set == NULL)
    6245             :                                 continue;
    6246             :                         break;
    6247             :                 }
    6248           0 :                 supported++;
    6249           0 :         }
    6250             : 
    6251           0 :         tp.tp_type = htons(tp_type);
    6252           0 :         tp.tp_length = htons((sizeof(oxm) * supported) + sizeof(tp));
    6253             : 
    6254           0 :         if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
    6255           0 :                 return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6256           0 :         *off += sizeof(tp);
    6257             : 
    6258           0 :         for (i = 0 ; i < nitems(ofp_oxm_handlers); i++) {
    6259           0 :                 switch (tp_type) {
    6260             :                 case OFP_TABLE_FEATPROP_MATCH:
    6261           0 :                         if (ofp_oxm_handlers[i].oxm_match == NULL)
    6262             :                                 continue;
    6263             :                         break;
    6264             :                 case OFP_TABLE_FEATPROP_WILDCARDS:
    6265           0 :                         if (ofp_oxm_handlers[i].oxm_match == NULL ||
    6266           0 :                             !(ofp_oxm_handlers[i].oxm_flags &
    6267             :                             SWOFP_MATCH_WILDCARD))
    6268             :                                 continue;
    6269             :                         break;
    6270             :                 case OFP_TABLE_FEATPROP_APPLY_SETFIELD:
    6271             :                 case OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS:
    6272             :                 case OFP_TABLE_FEATPROP_WRITE_SETFIELD:
    6273             :                 case OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS:
    6274           0 :                         if (ofp_oxm_handlers[i].oxm_set == NULL)
    6275             :                                 continue;
    6276             :                         break;
    6277             :                 }
    6278             : 
    6279           0 :                 memset(&oxm, 0, sizeof(oxm));
    6280           0 :                 OFP_OXM_SET_FIELD(&oxm, ofp_oxm_handlers[i].oxm_field);
    6281           0 :                 if ((tp_type == OFP_TABLE_FEATPROP_MATCH) &&
    6282           0 :                     (ofp_oxm_handlers[i].oxm_flags & SWOFP_MATCH_MASK))
    6283           0 :                         OFP_OXM_SET_HASMASK(&oxm);
    6284           0 :                 oxm.oxm_class = htons(OFP_OXM_C_OPENFLOW_BASIC);
    6285           0 :                 oxm.oxm_length = ofp_oxm_handlers[i].oxm_len;
    6286             : 
    6287           0 :                 if (m_copyback(m, *off, sizeof(oxm), (caddr_t)&oxm, M_NOWAIT))
    6288           0 :                         return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6289           0 :                 *off += sizeof(oxm);
    6290           0 :         }
    6291             : 
    6292             :         /*
    6293             :          * It's always 4 byte for padding becouse struct ofp_ox_mach and
    6294             :          * struct ofp_table_feature_property are 4 byte.
    6295             :          */
    6296           0 :         if ((supported & 0x1) == 0) {
    6297           0 :                 if (m_copyback(m, *off, sizeof(padding),
    6298             :                     (caddr_t)&padding, M_NOWAIT))
    6299           0 :                         return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6300           0 :                 *off += sizeof(padding);
    6301           0 :         }
    6302             : 
    6303           0 :         return (0);
    6304           0 : }
    6305             : 
    6306             : int
    6307           0 : swofp_table_features_put_actions(struct mbuf *m, int *off, uint16_t tp_type)
    6308             : {
    6309           0 :         struct ofp_table_feature_property        tp;
    6310           0 :         struct ofp_action_header                 action;
    6311             :         int                                      i, supported = 0;
    6312             :         int                                      actionlen, padsize;
    6313           0 :         uint8_t                                  padding[8];
    6314             : 
    6315           0 :         for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
    6316           0 :                 if (ofp_action_handlers[i].action)
    6317           0 :                         supported++;
    6318             :         }
    6319             : 
    6320             :         actionlen = sizeof(action) - sizeof(action.ah_pad);
    6321           0 :         tp.tp_type = htons(tp_type);
    6322           0 :         tp.tp_length = (actionlen * supported) + sizeof(tp);
    6323             : 
    6324           0 :         padsize = OFP_ALIGN(tp.tp_length) - tp.tp_length;
    6325           0 :         tp.tp_length = htons(tp.tp_length);
    6326             : 
    6327           0 :         if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
    6328           0 :                 return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6329           0 :         *off += sizeof(tp);
    6330             : 
    6331           0 :         for (i = 0 ; i < nitems(ofp_action_handlers); i++) {
    6332           0 :                 if (ofp_action_handlers[i].action == NULL)
    6333             :                         continue;
    6334             : 
    6335           0 :                 memset(&action, 0, actionlen);
    6336           0 :                 action.ah_type = ntohs(ofp_action_handlers[i].action_type);
    6337             :                 /* XXX action length is different for experimenter type. */
    6338           0 :                 action.ah_len = ntohs(actionlen);
    6339             : 
    6340           0 :                 if (m_copyback(m, *off, actionlen,
    6341             :                     (caddr_t)&action, M_NOWAIT))
    6342           0 :                         return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6343           0 :                 *off += actionlen;
    6344           0 :         }
    6345             : 
    6346           0 :         if (padsize) {
    6347           0 :                 memset(padding, 0, padsize);
    6348           0 :                 if (m_copyback(m, *off, padsize, &padding, M_NOWAIT))
    6349           0 :                         return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6350             : 
    6351           0 :                 *off += padsize;
    6352           0 :         }
    6353             : 
    6354           0 :         return (0);
    6355           0 : }
    6356             : 
    6357             : int
    6358           0 : swofp_table_features_put_instruction(struct mbuf *m, int *off, uint16_t tp_type)
    6359             : {
    6360           0 :         struct ofp_table_feature_property        tp;
    6361           0 :         struct ofp_instruction                   instructions[] =
    6362             :             {
    6363             :                 {
    6364             :                         htons(OFP_INSTRUCTION_T_GOTO_TABLE),
    6365             :                         htons(sizeof(struct ofp_instruction))
    6366             :                 },
    6367             :                 {
    6368             :                         htons(OFP_INSTRUCTION_T_WRITE_META),
    6369             :                         htons(sizeof(struct ofp_instruction))
    6370             :                 },
    6371             :                 {
    6372             :                         htons(OFP_INSTRUCTION_T_WRITE_ACTIONS),
    6373             :                         htons(sizeof(struct ofp_instruction))
    6374             :                 },
    6375             :                 {
    6376             :                         htons(OFP_INSTRUCTION_T_APPLY_ACTIONS),
    6377             :                         htons(sizeof(struct ofp_instruction))
    6378             :                 },
    6379             :                 {
    6380             :                         htons(OFP_INSTRUCTION_T_CLEAR_ACTIONS),
    6381             :                         htons(sizeof(struct ofp_instruction))
    6382             :                 },
    6383             :             };
    6384             : 
    6385           0 :         tp.tp_type = htons(tp_type);
    6386           0 :         tp.tp_length = htons(sizeof(instructions) + sizeof(tp));
    6387             : 
    6388           0 :         if (m_copyback(m, *off, sizeof(tp), (caddr_t)&tp, M_NOWAIT))
    6389           0 :                 return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6390           0 :         *off += sizeof(tp);
    6391             : 
    6392           0 :         if (m_copyback(m, *off, sizeof(instructions),
    6393           0 :             (caddr_t)instructions, M_NOWAIT))
    6394           0 :                 return (OFP_ERRREQ_MULTIPART_OVERFLOW);
    6395           0 :         *off += sizeof(instructions);
    6396             : 
    6397           0 :         return (0);
    6398           0 : }
    6399             : 
    6400             : int
    6401           0 : swofp_mp_recv_table_features(struct switch_softc *sc, struct mbuf *m)
    6402             : {
    6403           0 :         struct swofp_ofs                *ofs = sc->sc_ofs;
    6404             :         struct swofp_flow_table         *swft;
    6405             :         struct ofp_table_features       *tblf;
    6406             :         struct mbuf                     *n;
    6407           0 :         int                              off, error;
    6408           0 :         struct swofp_mpmsg               swmp;
    6409             : 
    6410           0 :         if ((error = swofp_mpmsg_reply_create(
    6411           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6412             :                 goto error;
    6413             : 
    6414           0 :         TAILQ_FOREACH(swft, &ofs->swofs_table_list, swft_table_next) {
    6415             :                 /* using mbuf becouse table featrues struct is variable length*/
    6416           0 :                 MGETHDR(n, M_DONTWAIT, MT_DATA);
    6417           0 :                 if (n == NULL)
    6418             :                         goto error;
    6419           0 :                 MCLGET(n, M_DONTWAIT);
    6420           0 :                 if ((n->m_flags & M_EXT) == 0) {
    6421           0 :                         m_freem(n);
    6422           0 :                         goto error;
    6423             :                 }
    6424           0 :                 n->m_len = n->m_pkthdr.len = sizeof(*tblf);
    6425             : 
    6426           0 :                 tblf = mtod(n, struct ofp_table_features *);
    6427           0 :                 memset(tblf, 0, sizeof(*tblf));
    6428           0 :                 tblf->tf_tableid = swft->swft_table_id;
    6429           0 :                 tblf->tf_metadata_match = UINT64_MAX;
    6430           0 :                 tblf->tf_metadata_write = UINT64_MAX;
    6431           0 :                 tblf->tf_config = 0;
    6432           0 :                 tblf->tf_max_entries = htonl(ofs->swofs_flow_max_entry);
    6433             : 
    6434           0 :                 off = sizeof(*tblf);
    6435           0 :                 if ((error = swofp_table_features_put_instruction(n, &off,
    6436             :                     OFP_TABLE_FEATPROP_INSTRUCTION)))
    6437             :                         goto error;
    6438             : 
    6439           0 :                 if ((error = swofp_table_features_put_instruction(n, &off,
    6440             :                     OFP_TABLE_FEATPROP_INSTRUCTION_MISS)))
    6441             :                         goto error;
    6442             : 
    6443           0 :                 if ((error = swofp_table_features_put_actions(n, &off,
    6444             :                     OFP_TABLE_FEATPROP_APPLY_ACTIONS)))
    6445             :                         goto error;
    6446             : 
    6447           0 :                 if ((error = swofp_table_features_put_actions(n, &off,
    6448             :                     OFP_TABLE_FEATPROP_APPLY_ACTIONS_MISS)))
    6449             :                         goto error;
    6450             : 
    6451           0 :                 if ((error = swofp_table_features_put_actions(n, &off,
    6452             :                     OFP_TABLE_FEATPROP_WRITE_ACTIONS)))
    6453             :                         goto error;
    6454             : 
    6455           0 :                 if ((error = swofp_table_features_put_actions(n, &off,
    6456             :                     OFP_TABLE_FEATPROP_WRITE_ACTIONS_MISS)))
    6457             :                         goto error;
    6458             : 
    6459           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6460             :                     OFP_TABLE_FEATPROP_MATCH)))
    6461             :                         goto error;
    6462             : 
    6463           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6464             :                     OFP_TABLE_FEATPROP_WILDCARDS)))
    6465             :                         goto error;
    6466             : 
    6467           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6468             :                     OFP_TABLE_FEATPROP_WRITE_SETFIELD)))
    6469             :                         goto error;
    6470             : 
    6471           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6472             :                     OFP_TABLE_FEATPROP_WRITE_SETFIELD_MISS)))
    6473             :                         goto error;
    6474             : 
    6475           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6476             :                     OFP_TABLE_FEATPROP_APPLY_SETFIELD)))
    6477             :                         goto error;
    6478             : 
    6479           0 :                 if ((error = swofp_table_features_put_oxm(n, &off,
    6480             :                     OFP_TABLE_FEATPROP_APPLY_SETFIELD_MISS)))
    6481             :                         goto error;
    6482             : 
    6483           0 :                 tblf->tf_length = htons(n->m_pkthdr.len);
    6484             : 
    6485           0 :                 if ((error = swofp_mpmsg_m_put(&swmp, n))) {
    6486           0 :                         m_freem(n);
    6487           0 :                         goto error;
    6488             :                 }
    6489             :         }
    6490             : 
    6491           0 :         m_freem(m);
    6492           0 :         return swofp_multipart_reply(sc, &swmp);
    6493             : 
    6494             :  error:
    6495           0 :         m_freem(m);
    6496           0 :         swofp_mpmsg_destroy(&swmp);
    6497           0 :         return (error);
    6498           0 : }
    6499             : 
    6500             : int
    6501           0 : swofp_mp_recv_port_desc(struct switch_softc *sc, struct mbuf *m)
    6502             : {
    6503           0 :         struct ofp_switch_port   swp;
    6504             :         struct switch_port      *swpo;
    6505           0 :         struct swofp_mpmsg       swmp;
    6506             :         struct ifnet            *ifs;
    6507             :         int                      error;
    6508             : 
    6509           0 :         if ((error = swofp_mpmsg_reply_create(
    6510           0 :             mtod(m, struct ofp_multipart *), &swmp))) {
    6511           0 :                 m_freem(m);
    6512           0 :                 return (error);
    6513             :         }
    6514             : 
    6515           0 :         TAILQ_FOREACH(swpo, &sc->sc_swpo_list, swpo_list_next) {
    6516           0 :                 memset(&swp, 0, sizeof(swp));
    6517           0 :                 ifs = if_get(swpo->swpo_ifindex);
    6518           0 :                 if (ifs == NULL)
    6519             :                         continue;
    6520             : 
    6521           0 :                 if (swpo->swpo_flags & IFBIF_LOCAL)
    6522           0 :                         swp.swp_number = htonl(OFP_PORT_LOCAL);
    6523             :                 else
    6524           0 :                         swp.swp_number = htonl(swpo->swpo_port_no);
    6525             : 
    6526           0 :                 memcpy(swp.swp_macaddr,
    6527             :                     ((struct arpcom *)ifs)->ac_enaddr, ETHER_ADDR_LEN);
    6528           0 :                 strlcpy(swp.swp_name, ifs->if_xname,
    6529             :                     sizeof(swp.swp_name));
    6530             : 
    6531           0 :                 if (!ISSET(ifs->if_flags, IFF_UP))
    6532           0 :                         swp.swp_config |= OFP_PORTCONFIG_PORT_DOWN;
    6533           0 :                 if (!ISSET(swpo->swpo_flags, IFBIF_STP))
    6534           0 :                         swp.swp_config |= OFP_PORTCONFIG_NO_STP;
    6535           0 :                 swp.swp_config = htonl(swp.swp_config);
    6536             : 
    6537           0 :                 if (!LINK_STATE_IS_UP(ifs->if_data.ifi_link_state))
    6538           0 :                         swp.swp_state |= OFP_PORTSTATE_LINK_DOWN;
    6539             : 
    6540           0 :                 if_put(ifs);
    6541             : 
    6542           0 :                 swp.swp_state = htonl(swp.swp_state);
    6543             :                 /* XXX how to get the if_media from ifp? ioctl? */
    6544           0 :                 swp.swp_cur = htonl(swp.swp_cur);
    6545           0 :                 swp.swp_advertised = htonl(swp.swp_advertised);
    6546           0 :                 swp.swp_supported = htonl(swp.swp_supported);
    6547           0 :                 swp.swp_peer = htonl(swp.swp_peer);
    6548             : 
    6549           0 :                 if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&swp,
    6550             :                     sizeof(swp))))
    6551             :                         goto error;
    6552             :         }
    6553             : 
    6554           0 :         m_freem(m);
    6555           0 :         return swofp_multipart_reply(sc, &swmp);
    6556             : 
    6557             :  error:
    6558           0 :         m_freem(m);
    6559           0 :         swofp_mpmsg_destroy(&swmp);
    6560           0 :         return (error);
    6561           0 : }
    6562             : 
    6563             : int
    6564           0 : swofp_mp_recv_group_desc(struct switch_softc *sc, struct mbuf *m)
    6565             : {
    6566           0 :         struct ofp_group_desc            ogd;
    6567             :         struct swofp_group_entry        *swge;
    6568           0 :         struct swofp_mpmsg               swmp;
    6569             :         int                              error;
    6570             : 
    6571           0 :         if ((error = swofp_mpmsg_reply_create(
    6572           0 :             mtod(m, struct ofp_multipart *), &swmp)))
    6573             :                 goto failed;
    6574             : 
    6575             : 
    6576           0 :         LIST_FOREACH(swge, &sc->sc_ofs->swofs_group_table, swge_next) {
    6577           0 :                 memset(&ogd, 0, sizeof(ogd));
    6578             : 
    6579           0 :                 ogd.gd_length = htons(offsetof(struct ofp_group_desc,
    6580             :                     gd_buckets) + swge->swge_buckets_len);
    6581           0 :                 ogd.gd_group_id = htonl(swge->swge_group_id);
    6582           0 :                 ogd.gd_type = swge->swge_type;
    6583             : 
    6584             :                 /*
    6585             :                  * Copy back GROUP DESC without buckets
    6586             :                  */
    6587           0 :                 if ((error = swofp_mpmsg_put(&swmp, (caddr_t)&ogd,
    6588             :                     sizeof(ogd))))
    6589             :                         goto failed;
    6590             : 
    6591             :                 /*
    6592             :                  * Copy back buckets on GROUP DESC
    6593             :                  */
    6594           0 :                 if (swge->swge_buckets != NULL &&
    6595           0 :                     (error = swofp_mpmsg_put(&swmp, (caddr_t)swge->swge_buckets,
    6596           0 :                     swge->swge_buckets_len)))
    6597             :                         goto failed;
    6598             :         }
    6599             : 
    6600           0 :         m_freem(m);
    6601           0 :         return swofp_multipart_reply(sc, &swmp);
    6602             : 
    6603             :  failed:
    6604           0 :         m_freem(m);
    6605           0 :         swofp_mpmsg_destroy(&swmp);
    6606           0 :         return (error);
    6607           0 : }
    6608             : 
    6609             : int
    6610           0 : swofp_barrier_req(struct switch_softc *sc, struct mbuf *m)
    6611             : {
    6612           0 :         swofp_barrier_reply(sc, m);
    6613           0 :         return 0;
    6614             : }
    6615             : 
    6616             : void
    6617           0 : swofp_barrier_reply(struct switch_softc *sc, struct mbuf *m)
    6618             : {
    6619             :         struct ofp_header       *oh;
    6620             : 
    6621           0 :         oh = mtod(m, struct ofp_header *);
    6622           0 :         oh->oh_type = OFP_T_BARRIER_REPLY;
    6623             : 
    6624           0 :         (void)swofp_output(sc, m);
    6625           0 : }

Generated by: LCOV version 1.13