/* *------------------------------------------------------------------ * flow_api.c - flow api * * Copyright (c) 2020 Intel and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define REPLY_MSG_ID_BASE flow_main.msg_id_base #include static inline void ipv4_addr_and_mask_convert (vl_api_ip4_address_and_mask_t * vl_api_addr, ip4_address_and_mask_t * vnet_addr) { clib_memcpy (vnet_addr, vl_api_addr, sizeof (*vnet_addr)); } static inline void ipv6_addr_and_mask_convert (vl_api_ip6_address_and_mask_t * vl_api_addr, ip6_address_and_mask_t * vnet_addr) { clib_memcpy (vnet_addr, vl_api_addr, sizeof (*vnet_addr)); } static inline void protocol_and_mask_convert (vl_api_ip_prot_and_mask_t * vl_api_protocol, ip_prot_and_mask_t * vnet_protocol) { vnet_protocol->prot = (ip_protocol_t) vl_api_protocol->prot; vnet_protocol->mask = vl_api_protocol->mask; } static inline void port_and_mask_convert (vl_api_ip_port_and_mask_t * vl_api_port, ip_port_and_mask_t * vnet_port) { vnet_port->port = ntohs (vl_api_port->port); vnet_port->mask = ntohs (vl_api_port->mask); } static inline void ipv4_flow_convert (vl_api_flow_ip4_t *vl_api_flow, vnet_flow_ip4_t *f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); } static void ipv6_flow_convert (vl_api_flow_ip6_t *vl_api_flow, vnet_flow_ip6_t *f) { ipv6_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv6_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); } static inline void ipv4_n_tuple_flow_convert (vl_api_flow_ip4_n_tuple_t * vl_api_flow, vnet_flow_ip4_n_tuple_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); } static void ipv6_n_tuple_flow_convert (vl_api_flow_ip6_n_tuple_t * vl_api_flow, vnet_flow_ip6_n_tuple_t * f) { ipv6_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv6_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); } static inline void ipv4_n_tuple_tagged_flow_convert (vl_api_flow_ip4_n_tuple_tagged_t * vl_api_flow, vnet_flow_ip4_n_tuple_tagged_t * f) { return ipv4_n_tuple_flow_convert ((vl_api_flow_ip4_n_tuple_t *) vl_api_flow, (vnet_flow_ip4_n_tuple_t *) f); } static inline void ipv6_n_tuple_tagged_flow_convert (vl_api_flow_ip6_n_tuple_tagged_t * vl_api_flow, vnet_flow_ip6_n_tuple_tagged_t * f) { return ipv6_n_tuple_flow_convert ((vl_api_flow_ip6_n_tuple_t *) vl_api_flow, (vnet_flow_ip6_n_tuple_t *) f); } static inline void ipv4_l2tpv3oip_flow_convert (vl_api_flow_ip4_l2tpv3oip_t * vl_api_flow, vnet_flow_ip4_l2tpv3oip_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); f->session_id = ntohl (vl_api_flow->session_id); } static inline void ipv4_ipsec_esp_flow_convert (vl_api_flow_ip4_ipsec_esp_t * vl_api_flow, vnet_flow_ip4_ipsec_esp_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); f->spi = ntohl (vl_api_flow->spi); } static inline void ipv4_ipsec_ah_flow_convert (vl_api_flow_ip4_ipsec_ah_t * vl_api_flow, vnet_flow_ip4_ipsec_ah_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); f->spi = ntohl (vl_api_flow->spi); } static inline void ipv4_vxlan_flow_convert (vl_api_flow_ip4_vxlan_t *vl_api_flow, vnet_flow_ip4_vxlan_t *f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); f->vni = ntohl (vl_api_flow->vni); } static inline void ipv6_vxlan_flow_convert (vl_api_flow_ip6_vxlan_t *vl_api_flow, vnet_flow_ip6_vxlan_t *f) { ipv6_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv6_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); f->vni = ntohl (vl_api_flow->vni); } static inline void ipv4_gtpu_flow_convert (vl_api_flow_ip4_gtpu_t * vl_api_flow, vnet_flow_ip4_gtpu_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); f->teid = ntohl (vl_api_flow->teid); } static inline void ipv4_gtpc_flow_convert (vl_api_flow_ip4_gtpc_t * vl_api_flow, vnet_flow_ip4_gtpc_t * f) { ipv4_addr_and_mask_convert (&vl_api_flow->src_addr, &f->src_addr); ipv4_addr_and_mask_convert (&vl_api_flow->dst_addr, &f->dst_addr); port_and_mask_convert (&vl_api_flow->src_port, &f->src_port); port_and_mask_convert (&vl_api_flow->dst_port, &f->dst_port); protocol_and_mask_convert (&vl_api_flow->protocol, &f->protocol); f->teid = ntohl (vl_api_flow->teid); } static inline void generic_flow_convert (vl_api_flow_generic_t *vl_api_flow, vnet_flow_generic_t *f) { clib_memcpy (f->pattern.spec, vl_api_flow->pattern.spec, sizeof (vl_api_flow->pattern.spec)); clib_memcpy (f->pattern.mask, vl_api_flow->pattern.mask, sizeof (vl_api_flow->pattern.mask)); } static void vl_api_flow_add_t_handler (vl_api_flow_add_t * mp) { vl_api_flow_add_reply_t *rmp; int rv = 0; vnet_flow_t flow; u32 flow_index = ~0; vl_api_flow_rule_t *f = &mp->flow; vnet_main_t *vnm = vnet_get_main (); flow.type = ntohl (f->type); flow.actions = ntohl (f->actions); flow.mark_flow_id = ntohl (f->mark_flow_id); flow.redirect_node_index = ntohl (f->redirect_node_index); flow.redirect_device_input_next_index = ntohl (f->redirect_device_input_next_index); flow.redirect_queue = ntohl (f->redirect_queue); flow.buffer_advance = ntohl (f->buffer_advance); switch (flow.type) { case VNET_FLOW_TYPE_IP4: ipv4_flow_convert (&f->flow.ip4, &flow.ip4); break; case VNET_FLOW_TYPE_IP6: ipv6_flow_convert (&f->flow.ip6, &flow.ip6); break; case VNET_FLOW_TYPE_IP4_N_TUPLE: ipv4_n_tuple_flow_convert (&f->flow.ip4_n_tuple, &flow.ip4_n_tuple); break; case VNET_FLOW_TYPE_IP6_N_TUPLE: ipv6_n_tuple_flow_convert (&f->flow.ip6_n_tuple, &flow.ip6_n_tuple); break; case VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED: ipv4_n_tuple_tagged_flow_convert (&f->flow.ip4_n_tuple_tagged, &flow.ip4_n_tuple_tagged); break; case VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED: ipv6_n_tuple_tagged_flow_convert (&f->flow.ip6_n_tuple_tagged, &flow.ip6_n_tuple_tagged); break; case VNET_FLOW_TYPE_IP4_L2TPV3OIP: ipv4_l2tpv3oip_flow_convert (&f->flow.ip4_l2tpv3oip, &flow.ip4_l2tpv3oip); break; case VNET_FLOW_TYPE_IP4_IPSEC_ESP: ipv4_ipsec_esp_flow_convert (&f->flow.ip4_ipsec_esp, &flow.ip4_ipsec_esp); break; case VNET_FLOW_TYPE_IP4_IPSEC_AH: ipv4_ipsec_ah_flow_convert (&f->flow.ip4_ipsec_ah, &flow.ip4_ipsec_ah); break; case VNET_FLOW_TYPE_IP4_VXLAN: ipv4_vxlan_flow_convert (&f->flow.ip4_vxlan, &flow.ip4_vxlan); break; case VNET_FLOW_TYPE_IP6_VXLAN: ipv6_vxlan_flow_convert (&f->flow.ip6_vxlan, &flow.ip6_vxlan); break; case VNET_FLOW_TYPE_IP4_GTPU: ipv4_gtpu_flow_convert (&f->flow.ip4_gtpu, &flow.ip4_gtpu); break; case VNET_FLOW_TYPE_IP4_GTPC: ipv4_gtpc_flow_convert (&f->flow.ip4_gtpc, &flow.ip4_gtpc); break; default: rv = VNET_FLOW_ERROR_NOT_SUPPORTED; goto out; break; } rv = vnet_flow_add (vnm, &flow, &flow_index); out: REPLY_MACRO2(VL_API_FLOW_ADD_REPLY, ({ rmp->flow_index = ntohl (flow_index); })); } static void vl_api_flow_add_v2_t_handler (vl_api_flow_add_v2_t *mp) { vl_api_flow_add_v2_reply_t *rmp; int rv = 0; vnet_flow_t flow; u32 flow_index = ~0; vl_api_flow_rule_v2_t *f = &mp->flow; vnet_main_t *vnm = vnet_get_main (); flow.type = ntohl (f->type); flow.actions = ntohl (f->actions); flow.mark_flow_id = ntohl (f->mark_flow_id); flow.redirect_node_index = ntohl (f->redirect_node_index); flow.redirect_device_input_next_index = ntohl (f->redirect_device_input_next_index); flow.redirect_queue = ntohl (f->redirect_queue); flow.buffer_advance = ntohl (f->buffer_advance); flow.queue_index = ntohl (f->queue_index); flow.queue_num = ntohl (f->queue_num); flow.rss_types = clib_net_to_host_u64 (f->rss_types); flow.rss_fun = ntohl (f->rss_fun); switch (flow.type) { case VNET_FLOW_TYPE_IP4: ipv4_flow_convert (&f->flow.ip4, &flow.ip4); break; case VNET_FLOW_TYPE_IP6: ipv6_flow_convert (&f->flow.ip6, &flow.ip6); break; case VNET_FLOW_TYPE_IP4_N_TUPLE: ipv4_n_tuple_flow_convert (&f->flow.ip4_n_tuple, &flow.ip4_n_tuple); break; case VNET_FLOW_TYPE_IP6_N_TUPLE: ipv6_n_tuple_flow_convert (&f->flow.ip6_n_tuple, &flow.ip6_n_tuple); break; case VNET_FLOW_TYPE_IP4_N_TUPLE_TAGGED: ipv4_n_tuple_tagged_flow_convert (&f->flow.ip4_n_tuple_tagged, &flow.ip4_n_tuple_tagged); break; case VNET_FLOW_TYPE_IP6_N_TUPLE_TAGGED: ipv6_n_tuple_tagged_flow_convert (&f->flow.ip6_n_tuple_tagged, &flow.ip6_n_tuple_tagged); break; case VNET_FLOW_TYPE_IP4_L2TPV3OIP: ipv4_l2tpv3oip_flow_convert (&f->flow.ip4_l2tpv3oip, &flow.ip4_l2tpv3oip); break; case VNET_FLOW_TYPE_IP4_IPSEC_ESP: ipv4_ipsec_esp_flow_convert (&f->flow.ip4_ipsec_esp, &flow.ip4_ipsec_esp); break; case VNET_FLOW_TYPE_IP4_IPSEC_AH: ipv4_ipsec_ah_flow_convert (&f->flow.ip4_ipsec_ah, &flow.ip4_ipsec_ah); break; case VNET_FLOW_TYPE_IP4_VXLAN: ipv4_vxlan_flow_convert (&f->flow.ip4_vxlan, &flow.ip4_vxlan); break; case VNET_FLOW_TYPE_IP6_VXLAN: ipv6_vxlan_flow_convert (&f->flow.ip6_vxlan, &flow.ip6_vxlan); break; case VNET_FLOW_TYPE_IP4_GTPU: ipv4_gtpu_flow_convert (&f->flow.ip4_gtpu, &flow.ip4_gtpu); break; case VNET_FLOW_TYPE_IP4_GTPC: ipv4_gtpc_flow_convert (&f->flow.ip4_gtpc, &flow.ip4_gtpc); break; case VNET_FLOW_TYPE_GENERIC: generic_flow_convert (&f->flow.generic, &flow.generic); break; default: rv = VNET_FLOW_ERROR_NOT_SUPPORTED; goto out; break; } rv = vnet_flow_add (vnm, &flow, &flow_index); out: REPLY_MACRO2 (VL_API_FLOW_ADD_V2_REPLY, ({ rmp->flow_index = ntohl (flow_index); })); } static void vl_api_flow_del_t_handler (vl_api_flow_del_t * mp) { vl_api_flow_add_reply_t *rmp; int rv = 0; vnet_main_t *vnm = vnet_get_main (); rv = vnet_flow_del (vnm, ntohl (mp->flow_index)); REPLY_MACRO (VL_API_FLOW_DEL_REPLY); } static void vl_api_flow_enable_t_handler (vl_api_flow_enable_t * mp) { vl_api_flow_add_reply_t *rmp; int rv = 0; vnet_main_t *vnm = vnet_get_main (); rv = vnet_flow_enable (vnm, ntohl (mp->flow_index), ntohl (mp->hw_if_index)); REPLY_MACRO (VL_API_FLOW_ENABLE_REPLY); } static void vl_api_flow_disable_t_handler (vl_api_flow_disable_t * mp) { vl_api_flow_add_reply_t *rmp; int rv = 0; vnet_main_t *vnm = vnet_get_main (); rv = vnet_flow_disable (vnm, ntohl (mp->flow_index), ntohl (mp->hw_if_index)); REPLY_MACRO (VL_API_FLOW_DISABLE_REPLY); } #include static clib_error_t * hw_flow_api_hookup (vlib_main_t * vm) { flow_main.msg_id_base = setup_message_id_table (); return 0; } VLIB_API_INIT_FUNCTION (hw_flow_api_hookup); /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */