/* // Copyright (c) 2010-2017 Intel Corporation // // 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 // required by rte_eth_ctrl.h in 19.05 #include #include "log.h" #include "quit.h" #include "lconf.h" #include "task_init.h" #include "task_base.h" #include "kv_store_expire.h" #include "stats.h" #include "prox_shared.h" #include "etypes.h" #include "prox_cfg.h" #include "dpi/dpi.h" struct task_dpi_per_core { void *dpi_opaque; }; struct task_fm { struct task_base base; /* FM related fields */ struct kv_store_expire *kv_store_expire; void *dpi_opaque; struct dpi_engine dpi_engine; struct task_dpi_per_core *dpi_shared; /* Used only during init */ }; struct eth_ip4_udp { struct ether_hdr l2; struct ipv4_hdr l3; union { struct udp_hdr udp; struct tcp_hdr tcp; } l4; } __attribute__((packed)); union pkt_type { struct { uint16_t etype; uint8_t ip_byte; uint8_t next_proto; } __attribute__((packed)); uint32_t val; }; static union pkt_type pkt_type_udp = { .next_proto = IPPROTO_UDP, .ip_byte = 0x45, .etype = ETYPE_IPv4, }; static union pkt_type pkt_type_tcp = { .next_proto = IPPROTO_TCP, .ip_byte = 0x45, .etype = ETYPE_IPv4, }; static int extract_flow_info(struct eth_ip4_udp *p, struct flow_info *fi, struct flow_info *fi_flipped, uint32_t *len, uint8_t **payload) { union pkt_type pkt_type = { .next_proto = p->l3.next_proto_id, .ip_byte = p->l3.version_ihl, .etype = p->l2.ether_type, }; memset(fi->reservered, 0, sizeof(fi->reservered)); memset(fi_flipped->reservered, 0, sizeof(fi_flipped->reservered)); if (pkt_type.val == pkt_type_udp.val) { fi->ip_src = p->l3.src_addr; fi->ip_dst = p->l3.dst_addr; fi->ip_proto = p->l3.next_proto_id; fi->port_src = p->l4.udp.src_port; fi->port_dst = p->l4.udp.dst_port; fi_flipped->ip_src = p->l3.dst_addr; fi_flipped->ip_dst = p->l3.src_addr; fi_flipped->ip_proto = p->l3.next_proto_id; fi_flipped->port_src = p->l4.udp.dst_port; fi_flipped->port_dst = p->l4.udp.src_port; *len = rte_be_to_cpu_16(p->l4.udp.dgram_len) - sizeof(struct udp_hdr); *payload = (uint8_t*)(&p->l4.udp) + sizeof(struct udp_hdr); return 0; } else if (pkt_type.val == pkt_type_tcp.val) { fi->ip_src = p->l3.src_addr; fi->ip_dst = p->l3.dst_addr; fi->ip_proto = p->l3.next_proto_id; fi->port_src = p->l4.tcp.src_port; fi->port_dst = p->l4.tcp.dst_port; fi_flipped->ip_src = p->l3.dst_addr; fi_flipped->ip_dst = p->l3.src_addr; fi_flipped->ip_proto = p->l3.next_proto_id; fi_flipped->port_src = p->l4.tcp.dst_port; fi_flipped->port_dst = p->l4.tcp.src_port; *len = rte_be_to_cpu_16(p->l3.total_length) - sizeof(struct ipv4_hdr) - ((p->l4.tcp.data_off >> 4)*4); *payload = ((uint8_t*)&p->l4.tcp) + ((p->l4.tcp.data_off >> 4)*4); return 0; } return -1; } static int is_flow_beg(const struct flow_info *fi, const struct eth_ip4_udp *p) { return fi->ip_proto == IPPROTO_UDP || (fi->ip_proto == IPPROTO_TCP && p->l4.tcp.tcp_flags & TCP_SYN_FLAG); } static void *lookup_flow(struct task_fm *task, struct flow_info *fi, uint64_t now_tsc) { struct kv_store_expire_entry *entry; entry = kv_store_expire_get(task->kv_store_expire, fi, now_tsc); return entry ? entry_value(task->kv_store_expire, entry) : NULL; } static void *lookup_or_insert_flow(struct task_fm *task, struct flow_info *fi, uint64_t now_tsc) { struct kv_store_expire_entry *entry; entry = kv_store_expire_get_or_put(task->kv_store_expire, fi, now_tsc); return entry ? entry_value(task->kv_store_expire, entry) : NULL; } static int handle_fm(struct task_fm *task, struct rte_mbuf *mbuf, uint64_t now_tsc) { struct eth_ip4_udp *p; struct flow_info fi, fi_flipped; void *flow_data; uint32_t len; uint8_t *payload; uint32_t res[2]; size_t res_len = 2; int flow_beg; struct dpi_payload dpi_payload; int is_upstream = 0; p = rte_pktmbuf_mtod(mbuf, struct eth_ip4_udp *); if (0 != extract_flow_info(p, &fi, &fi_flipped, &len, &payload)) { plogx_err("Unknown packet type\n"); return OUT_DISCARD; } /* First, try to see if the flow already exists where the current packet is sent by the server. */ if (!(flow_data = lookup_flow(task, &fi_flipped, now_tsc))) { /* Insert a new flow, only if this is the first packet in the flow. */ is_upstream = 1; if (is_flow_beg(&fi, p)) flow_data = lookup_or_insert_flow(task, &fi, now_tsc); else flow_data = lookup_flow(task, &fi, now_tsc); } if (!flow_data) return OUT_DISCARD; else if (!len) return 0; dpi_payload.payload = payload; dpi_payload.len = len; dpi_payload.client_to_server = is_upstream; gettimeofday(&dpi_payload.tv, NULL); task->dpi_engine.dpi_process(task->dpi_opaque, is_upstream? &fi : &fi_flipped, flow_data, &dpi_payload, res, &res_len); return OUT_HANDLED; } static int handle_fm_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts) { struct task_fm *task = (struct task_fm *)tbase; uint64_t now_tsc = rte_rdtsc(); uint16_t handled = 0; uint16_t discard = 0; int ret; for (uint16_t i = 0; i < n_pkts; ++i) { ret =