├── .gitignore ├── LICENSE ├── README ├── dpdk └── firewall │ ├── Makefile │ ├── acl.c │ ├── acl.h │ ├── arp.c │ ├── config.c │ ├── control.c │ ├── etc │ ├── build_rules.py │ ├── pipeline.conf │ └── zones │ │ ├── default.conf │ │ └── ixia_tests.conf │ ├── firewall.c │ ├── forward.h │ ├── frag.c │ ├── frag.h │ ├── iface.c │ ├── init.c │ ├── io.c │ ├── ip6.h │ ├── kni.c │ ├── main.c │ ├── main.h │ ├── nat.c │ ├── nat.h │ ├── packet.c │ ├── packet.h │ ├── rollhash.h │ ├── routing.h │ ├── runtime.c │ ├── runtime.h │ ├── strlcat.c │ ├── strlcpy.c │ ├── strutil.h │ ├── synauth.c │ ├── synauth.h │ ├── tap.c │ ├── util.c │ ├── util.h │ ├── worker.c │ └── zone.h └── tests └── raw.c /.gitignore: -------------------------------------------------------------------------------- 1 | dpdk/firewall/.cproject 2 | dpdk/firewall/.project 3 | dpdk/firewall/.pydevproject 4 | dpdk/firewall/.settings 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD LICENSE 2 | 3 | Copyright (c) 2015, SAPO 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Just prototyping some network stuff. 2 | 3 | He be dragons: the code has not seen any kind of review (security or other). 4 | -------------------------------------------------------------------------------- /dpdk/firewall/Makefile: -------------------------------------------------------------------------------- 1 | # BSD LICENSE 2 | # 3 | # Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 4 | # All rights reserved. 5 | # 6 | # Redistribution and use in source and binary forms, with or without 7 | # modification, are permitted provided that the following conditions 8 | # are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright 11 | # notice, this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in 14 | # the documentation and/or other materials provided with the 15 | # distribution. 16 | # * Neither the name of Intel Corporation nor the names of its 17 | # contributors may be used to endorse or promote products derived 18 | # from this software without specific prior written permission. 19 | # 20 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | ifeq ($(RTE_SDK),) 33 | $(error "Please define RTE_SDK environment variable") 34 | endif 35 | 36 | # Default target, can be overriden by command line or environment 37 | RTE_TARGET ?= x86_64-native-linuxapp-gcc 38 | 39 | include $(RTE_SDK)/mk/rte.vars.mk 40 | 41 | # binary name 42 | APP = firewall 43 | 44 | # all source are stored in SRCS-y 45 | SRCS-y := main.c strlcpy.c strlcat.c config.c init.c io.c runtime.c 46 | SRCS-y += worker.c firewall.c kni.c tap.c acl.c nat.c util.c 47 | SRCS-y += control.c arp.c iface.c packet.c frag.c synauth.c 48 | 49 | #CFLAGS += -O3 -g 50 | CFLAGS += -O0 -g -DDEBUG 51 | CFLAGS += $(WERROR_FLAGS) 52 | CFLAGS += -DMAX_NIC_PORTS=6 -DMAX_LCORES=16 53 | CFLAGS += -DMAX_IO_LCORES=8 -DMAX_WORKER_LCORES=8 54 | CFLAGS += -D_GNU_SOURCE -D_LGPL_SOURCE 55 | 56 | LDFLAGS += -lconfig 57 | LDFLAGS += -lurcu-qsbr 58 | LDFLAGS += -lcrypto 59 | 60 | # workaround for a gcc bug with noreturn attribute 61 | # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603 62 | ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y) 63 | CFLAGS_main.o += -Wno-return-type 64 | endif 65 | 66 | include $(RTE_SDK)/mk/rte.extapp.mk 67 | -------------------------------------------------------------------------------- /dpdk/firewall/acl.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef ACL_H_ 36 | #define ACL_H_ 37 | 38 | #include 39 | #include 40 | 41 | #include "main.h" 42 | #include "zone.h" 43 | 44 | #define MAX_ACL_CATEGORIES 1 45 | 46 | /* 47 | * These flags must be kept in sync with build_rules.py 48 | * 49 | * Please note that bits 0-4 (MSB ordering) are reserved for 50 | * rule statistics purposes. 51 | */ 52 | #define ACL_ACTION_ACCEPT 1 << 0 53 | #define ACL_ACTION_DROP 1 << 1 54 | #define ACL_ACTION_LOCAL 1 << 2 55 | #define ACL_ACTION_SNAT 1 << 3 56 | #define ACL_ACTION_DNAT 1 << 4 57 | #define ACL_ACTION_COUNT 1 << 5 58 | #define ACL_ACTION_MONIT 1 << 6 59 | #define ACL_ACTION_SYNAUTH 1 << 7 60 | 61 | #define UDATA_BITS (sizeof(uint32_t) * 8) 62 | #define COUNT_BITS (4) 63 | #define COUNT_SHIFT (UDATA_BITS - COUNT_BITS) 64 | 65 | #define ACL_COUNT_ID(udata) ((udata >> COUNT_SHIFT) & 0x0f) 66 | 67 | struct acl_counter { 68 | uint64_t packets; 69 | uint64_t bytes; 70 | }; 71 | 72 | struct acl_ctx { 73 | const uint8_t *ip_data[BATCH_SIZE_ACL]; 74 | struct rte_mbuf *ip_m[BATCH_SIZE_ACL]; 75 | uint32_t ip_res[BATCH_SIZE_ACL]; 76 | uint16_t n_ip; 77 | 78 | const uint8_t *ip6_data[BATCH_SIZE_ACL]; 79 | struct rte_mbuf *ip6_m[BATCH_SIZE_ACL]; 80 | uint32_t ip6_res[BATCH_SIZE_ACL]; 81 | uint16_t n_ip6; 82 | }; 83 | 84 | int acl_parse_rules(struct zone_cfg *); 85 | void acl_free_rules(struct zone_cfg *); 86 | 87 | #endif /* ACL_H_ */ 88 | -------------------------------------------------------------------------------- /dpdk/firewall/arp.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | 32 | #include "main.h" 33 | #include "util.h" 34 | #include "runtime.h" 35 | #include "packet.h" 36 | #include "forward.h" 37 | 38 | #define ARP_UPDATE_US 30 * US_PER_S 39 | #define ARP_PROBE_US 1 * US_PER_S 40 | #define ARP_PROBE_RETRY_US 30 * US_PER_S 41 | #define ARP_MAX_PROBES 10 42 | 43 | static struct gw_addr * 44 | gw_info(uint16_t vlan_tci, in_addr_t addr) 45 | { 46 | int i; 47 | 48 | if (PKT_VLANID(vlan_tci) == cfg.ovlan) { 49 | for (i = 0; i < cfg.n_ogws; i++) { 50 | if (addr == cfg.ogws[i].ip.s_addr) { 51 | return &cfg.ogws[i]; 52 | } 53 | } 54 | return NULL; 55 | } 56 | for (i = 0; i < cfg.n_igws; i++) { 57 | if (addr == cfg.igws[i].ip.s_addr) { 58 | return &cfg.igws[i]; 59 | } 60 | } 61 | 62 | return NULL; 63 | } 64 | 65 | static inline void 66 | print_mac_addr(const uint8_t *addr, struct in_addr ip, uint8_t port) 67 | { 68 | char a, b, c, d; 69 | uint32_to_char(ip.s_addr, &a, &b, &c, &d); 70 | LOG(DEBUG, USER1, "%4s updating table. Port %u, " 71 | "%hhu.%hhu.%hhu.%hhu -> %02x:%02x:%02x:%02x:%02x:%02x.\n", 72 | "ARP", port, d, c, b, a, 73 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); 74 | } 75 | 76 | static struct gw_addr * 77 | update_from_arp(const struct rte_mbuf *m, const uint8_t *data, uint64_t now) 78 | { 79 | const struct ether_arp *ea; 80 | struct gw_addr *gwa; 81 | in_addr_t *ip; 82 | 83 | if ((ea = pkt_ether_arp_hdr(m, data)) == NULL) { 84 | RTE_LOG(DEBUG, USER1, "WRK: Not a valid ARP packet.\n"); 85 | return NULL; 86 | } 87 | if ((_ntohs(ea->arp_op) & (ARPOP_REQUEST | ARPOP_REPLY)) == 0) { 88 | RTE_LOG(DEBUG, USER1, "WRK: Not an ARP request or reply.\n"); 89 | return NULL; 90 | } 91 | /* Check if the ARP packet is from a gateway */ 92 | ip = (in_addr_t *)&ea->arp_spa; 93 | if ((gwa = gw_info(m->vlan_tci, *ip)) == NULL) { 94 | char a, b, c, d; 95 | uint32_to_char(_htonl(*ip), &a, &b, &c, &d); 96 | if (*ip != cfg.vlans[PKT_VLANID(m->vlan_tci)].ip.s_addr) { 97 | RTE_LOG(DEBUG, USER1, "Ignoring ARP. " 98 | "srcip: %hhu.%hhu.%hhu.%hhu, vlan: %u, port: %u\n", 99 | a, b, c, d, PKT_VLANID(m->vlan_tci), m->port); 100 | } 101 | return NULL; 102 | } 103 | if (memcmp(&ea->arp_sha, &gwa->mac, ETHER_ADDR_LEN) == 0) { 104 | //RTE_LOG(DEBUG, USER1, "Already have latest mac address. " 105 | // "Ignoring...\n"); 106 | gwa->update_ts = now; 107 | return NULL; 108 | } 109 | ether_addr_copy(&ea->arp_sha, &gwa->mac); 110 | print_mac_addr((uint8_t *)&gwa->mac, gwa->ip, m->port); 111 | 112 | return gwa; 113 | } 114 | 115 | static struct gw_addr * 116 | update_from_ip(const struct rte_mbuf *m, const uint8_t *data, uint64_t now) 117 | { 118 | const struct ether_hdr *eh; 119 | const struct ipv4_hdr *ih; 120 | struct gw_addr *gwa; 121 | 122 | eh = (const struct ether_hdr *)data; 123 | ih = (const struct ipv4_hdr *)(data + sizeof(struct ether_hdr)); 124 | 125 | /* Check if the ARP packet is from a gateway */ 126 | if ((gwa = gw_info(m->vlan_tci, ih->src_addr)) == NULL) { 127 | //LOG(DEBUG, USER1, "%4s packet not from known gateway.\n", 128 | //"ARP"); 129 | return NULL; 130 | } 131 | if (memcmp(&eh->s_addr, &gwa->mac, ETHER_ADDR_LEN) == 0) { 132 | //LOG(DEBUG, USER1, "%4s already have latest mac address. " 133 | // "Ignoring...\n", "ARP"); 134 | gwa->update_ts = now; 135 | return NULL; 136 | } 137 | ether_addr_copy(&eh->s_addr, &gwa->mac); 138 | print_mac_addr((uint8_t *)&gwa->mac, gwa->ip, m->port); 139 | 140 | return gwa; 141 | } 142 | 143 | static struct rte_mbuf * 144 | create_request(in_addr_t ip, uint16_t vlan) 145 | { 146 | struct rte_mbuf *m; 147 | struct rte_mempool *pool; 148 | struct ether_hdr *eh; 149 | struct ether_arp *ah; 150 | uint8_t *data; 151 | static struct ether_addr brd = { 152 | .addr_bytes = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} 153 | }; 154 | 155 | pool = cfg.pools[rte_socket_id()]; 156 | m = rte_pktmbuf_alloc(pool); 157 | if (m == NULL) { 158 | return NULL; 159 | } 160 | data = rte_pktmbuf_mtod(m, uint8_t *); 161 | eh = (struct ether_hdr *)data; 162 | ah = (struct ether_arp *)(data + sizeof(struct ether_hdr)); 163 | 164 | /* Ethernet header */ 165 | ether_addr_copy(&cfg.ifaces[0].hwaddr, &eh->s_addr); 166 | ether_addr_copy(&brd, &eh->d_addr); 167 | eh->ether_type = _htons(ETHER_TYPE_ARP); 168 | 169 | /* ARP header */ 170 | ah->ea_hdr.ar_hrd = _htons(ARPHRD_ETHER); 171 | ah->ea_hdr.ar_pro = _htons(ETHER_TYPE_IPv4); 172 | ah->ea_hdr.ar_hln = ETHER_ADDR_LEN; 173 | ah->ea_hdr.ar_pln = sizeof(struct in_addr); 174 | ah->ea_hdr.ar_op = _htons(ARPOP_REQUEST); 175 | 176 | rte_memcpy(&ah->arp_spa, &cfg.vlans[vlan].ip, sizeof(ah->arp_spa)); 177 | rte_memcpy(&ah->arp_tpa, &ip, sizeof(ah->arp_tpa)); 178 | rte_memcpy(&ah->arp_sha, &cfg.ifaces[0].hwaddr, sizeof(ah->arp_sha)); 179 | rte_memcpy(&ah->arp_tha, &brd, sizeof(ah->arp_tha)); 180 | 181 | m->pkt_len = sizeof(struct ether_hdr) + sizeof(struct ether_arp); 182 | m->data_len = sizeof(struct ether_hdr) + sizeof(struct ether_arp); 183 | m->nb_segs = 1; 184 | m->next = NULL; 185 | m->vlan_tci = vlan; 186 | 187 | /* TODO: choose port randomly? */ 188 | m->port = 0; 189 | 190 | /* Let the forwarding code know that no routing decision is required */ 191 | m->udata64 = PKT_META_ROUTED; 192 | 193 | return m; 194 | } 195 | 196 | struct gw_addr * 197 | arp_chk_gw_pkt(struct rte_mbuf *m, uint64_t now) 198 | { 199 | if (PKT_TYPE(m) == RTE_PTYPE_L2_ETHER_ARP) { 200 | return update_from_arp(m, rte_pktmbuf_mtod(m, uint8_t *), now); 201 | } 202 | if ((m->udata64 & PKT_META_LOCAL) && PKT_TYPE(m) == RTE_PTYPE_L3_IPV4) { 203 | return update_from_ip(m, rte_pktmbuf_mtod(m, uint8_t *), now); 204 | } 205 | return NULL; 206 | } 207 | 208 | void 209 | arp_send_probes(struct worker_lc_cfg *lp, struct gw_addr *gws, 210 | uint32_t n_gws, uint64_t tsc_per_us) 211 | { 212 | uint32_t i; 213 | 214 | for (i = 0; i < n_gws; i++) { 215 | struct rte_mbuf *m; 216 | 217 | /* Entry is up to date or being throttled */ 218 | if (now_tsc - gws[i].update_ts < US2TSC(ARP_UPDATE_US) || 219 | now_tsc - gws[i].probe_ts < US2TSC(ARP_PROBE_US)) { 220 | continue; 221 | } 222 | if (gws[i].probes > ARP_MAX_PROBES) { 223 | /* Not yet ready to start sending ARP probes */ 224 | if (now_tsc - 225 | gws[i].probe_ts < US2TSC(ARP_PROBE_RETRY_US)) { 226 | continue; 227 | } 228 | /* Start probing again */ 229 | gws[i].probes = 0; 230 | } 231 | /* Ensure that we have a configured address for the vlan */ 232 | if (unlikely(cfg.vlans[gws[i].vlan].ip.s_addr == 0)) { 233 | continue; 234 | } 235 | char a, b, c, d; 236 | uint32_to_char(gws[i].ip.s_addr, &d, &c, &b, &a); 237 | //LOG(DEBUG, USER1, "%4s sending probe for: " 238 | // "%hhu.%hhu.%hhu.%hhu vlan: %" PRIu16 "\n", 239 | //"ARP", a, b, c, d, gws[i].vlan); 240 | m = create_request(gws[i].ip.s_addr, gws[i].vlan); 241 | if (m == NULL) { 242 | /* TODO: log error */ 243 | continue; 244 | } 245 | gws[i].probes++; 246 | gws[i].probe_ts = now_tsc; 247 | 248 | fwd_nic_pkt(m, lp); 249 | } 250 | } 251 | -------------------------------------------------------------------------------- /dpdk/firewall/control.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include 44 | 45 | #include "main.h" 46 | #include "packet.h" 47 | #include "runtime.h" 48 | #include "forward.h" 49 | 50 | struct ctrl_cron { 51 | /* When these values are reached, run the job */ 52 | uint64_t next; 53 | uint64_t refresh_arp; 54 | uint64_t update_arp; 55 | uint64_t refresh_vlans; 56 | uint64_t flush; 57 | uint64_t lacp; 58 | uint64_t kni; 59 | 60 | /* These timestamps specify when the job last ran */ 61 | uint64_t last_stats; 62 | }; 63 | 64 | uint64_t tsc_per_us; 65 | uint64_t volatile now_tsc; 66 | 67 | static inline void 68 | refresh_vlans(uint64_t now, struct ctrl_cron *cron) 69 | { 70 | 71 | if (likely(now < cron->refresh_vlans)) { 72 | return; 73 | } 74 | if (scan_vlans()) { 75 | cfg.vlans_ts = now; 76 | } 77 | cron->refresh_vlans = now + US2TSC(TASK_REFRESH_VLANS_US); 78 | } 79 | 80 | static inline void 81 | refresh_arp_table(struct worker_lc_cfg *lp, struct ctrl_cron *cron) 82 | { 83 | 84 | if (likely(now_tsc < cron->refresh_arp)) { 85 | return; 86 | } 87 | arp_send_probes(lp, cfg.igws, cfg.n_igws, tsc_per_us); 88 | arp_send_probes(lp, cfg.ogws, cfg.n_ogws, tsc_per_us); 89 | 90 | cron->refresh_arp = now_tsc + US2TSC(TASK_REFRESH_ARP_US); 91 | 92 | } 93 | 94 | static inline void 95 | negotiate_lacp(void) 96 | { 97 | int i; 98 | 99 | for (i = 0; i < MAX_NIC_PORTS; i++) { 100 | if (cfg.ifaces[i].flags & NIC_FLAG_BOND_IFACE) { 101 | cfg.ifaces[i].lacp = 1; 102 | } 103 | } 104 | } 105 | 106 | static inline void 107 | flush_kni(struct worker_lc_cfg *lp, struct ctrl_cron *cron) 108 | { 109 | enum worker_type ktype; 110 | uint32_t i; 111 | 112 | ktype = WORKER_TYPE_CTRL_KNI; 113 | 114 | if (likely(lp->type != ktype || now_tsc < cron->kni)) { 115 | return; 116 | } 117 | for (i = 0; i < lp->kni.n_kni; i++) { 118 | rte_kni_handle_request(lp->kni.kni[i]); 119 | } 120 | 121 | cron->kni = now_tsc + US2TSC(TASK_KNI_US); 122 | 123 | } 124 | 125 | static inline void 126 | run_tasks(struct worker_lc_cfg *lp, struct ctrl_cron *cron) 127 | { 128 | 129 | refresh_vlans(now_tsc, cron); 130 | refresh_arp_table(lp, cron); 131 | wrk_pkt_stats(lp, &cron->last_stats); 132 | flush_kni(lp, cron); 133 | 134 | if (unlikely(reload_fw)) { 135 | fw_reload(); 136 | reload_fw = 0; 137 | } 138 | if (unlikely(dump_fw_counters)) { 139 | fw_dump_counters(); 140 | dump_fw_counters = 0; 141 | } 142 | } 143 | 144 | void 145 | ctrl_lcore_main_loop(struct worker_lc_cfg *lp) 146 | { 147 | struct ctrl_cron cron = {0}; 148 | uint32_t burst, idle; 149 | uint32_t (*fwd_pkts_to_kernel) (struct worker_lc_cfg *, uint32_t); 150 | uint32_t (*fwd_pkts_to_nic) (struct worker_lc_cfg *, uint32_t); 151 | 152 | burst = cfg.worker_read_burst_size; 153 | 154 | /* Only use the TAP for now */ 155 | fwd_pkts_to_kernel = tap_fwd_pkts_to_kernel; 156 | fwd_pkts_to_nic = tap_fwd_pkts_to_nic; 157 | 158 | idle = 0; 159 | for (;;) { 160 | now_tsc = rte_rdtsc(); 161 | 162 | if (unlikely(now_tsc > cron.flush)) { 163 | if (lp->pending) { 164 | lp->pending = 0; 165 | flush_nic_buffers(lp); 166 | } 167 | cron.flush = now_tsc + US2TSC(LCORE_WORKER_FLUSH_US); 168 | } 169 | if (unlikely(now_tsc > cron.lacp)) { 170 | negotiate_lacp(); 171 | cron.lacp = now_tsc + US2TSC(TASK_NEGO_LACP_US); 172 | } 173 | if (unlikely(now_tsc > cron.next)) { 174 | run_tasks(lp, &cron); 175 | cron.next = now_tsc + US2TSC(LCORE_CTRL_TASKS_US); 176 | } 177 | /* Forward received packets to kernel */ 178 | if (fwd_pkts_to_kernel(lp, burst)) { 179 | idle = 0; 180 | } 181 | /* Forward kernel packets to NIC ports */ 182 | if (fwd_pkts_to_nic(lp, burst)) { 183 | idle = 0; 184 | } 185 | idle_heuristic(idle); 186 | if (lp->pending == 0) { 187 | idle++; 188 | } else { 189 | idle = 0; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /dpdk/firewall/etc/pipeline.conf: -------------------------------------------------------------------------------- 1 | name = "SAPO Firewall" 2 | 3 | # Network interfaces 4 | ifaces = ( 5 | { port = 0; reverse = false; zone = "default"; } 6 | # { port = 1; reverse = false; zone = "default"; }, 7 | # { port = 2; reverse = false; zone = "default"; }, 8 | # { port = 3; reverse = false; zone = "default"; }, 9 | # { port = 4; reverse = false; zone = "default"; bond = [0, 1, 2, 3]; } 10 | ); 11 | 12 | # Routing settings 13 | routing = 14 | { 15 | inside_gws = [ 16 | "192.168.201.11" 17 | #"192.168.201.2", 18 | #"192.168.201.3", 19 | #"192.168.201.4" 20 | ]; 21 | inside_vlan = 201; 22 | 23 | outside_gws = [ 24 | "192.168.202.11" 25 | #"192.168.202.2", 26 | #"192.168.202.3", 27 | #"192.168.202.4" 28 | ]; 29 | outside_vlan = 202; 30 | 31 | # For the following hosts, use a more conservative 32 | # gateway selection method (remote IP only). 33 | # Usually, this is required for hosts that are providing services through 34 | # specific protocols that do not play nice with NAT (e.g., FTP, IRC, Amanda) 35 | # By placing a host in this list, we ensure that the same gateway will 36 | # handle all requests for a given client 37 | conservative = ["10.0.0.1", "1.2.3.4"]; 38 | 39 | # IP reassembly settings 40 | frag_max_flow_num = 10000; 41 | frag_max_flow_ttl = 5; 42 | }; 43 | 44 | # IO cores 45 | io_lcores = ( 46 | { 47 | lcore = 1; 48 | type = "rx"; 49 | # The e1000 nic supports only one queue 50 | queues = ( 51 | # { port = 4; queue = 0; } 52 | { port = 0; queue = 0; } 53 | ); 54 | workers = (0, 1); 55 | }, 56 | { 57 | lcore = 2; 58 | type = "tx"; 59 | ports = (0); 60 | } 61 | ); 62 | 63 | # Workers 64 | worker_lcores = ( 65 | 66 | # Worker 0 - firewall 67 | { 68 | lcore = 3; 69 | type = "fw"; 70 | kni = true; 71 | offload_type = 1; 72 | }, 73 | 74 | # Worker 1 - firewall 75 | { 76 | lcore = 4; 77 | type = "fw"; 78 | kni = true; 79 | offload_type = 1; 80 | }, 81 | 82 | # Worker 2 - Control 83 | { 84 | lcore = 0; 85 | type = "control"; 86 | kni_type = "tap"; 87 | master = true; 88 | ports = (0); 89 | }, 90 | 91 | # Worker 3 - Firewall and offloader (ip frag reassembly, syn authentication) 92 | { 93 | lcore = 6; 94 | type = "fw"; 95 | kni = false; 96 | offload_type = 2; 97 | } 98 | ); 99 | -------------------------------------------------------------------------------- /dpdk/firewall/etc/zones/default.conf: -------------------------------------------------------------------------------- 1 | # NAT 2 | # nft add rule nat pre ip daddr 192.168.200.1 dnat 192.168.66.11 3 | 4 | # Local rules 5 | # nft add rule filter input icmp accept 6 | 7 | # Forwaring rules 8 | nft add rule filter forward ip daddr 192.168.66.11 icmp accept 9 | nft add rule filter forward ip daddr 192.168.66.11 tcp dport 8888 accept synauth 10 | nft add rule filter forward ip daddr 192.168.66.11 tcp dport 22 accept 11 | 12 | nft add rule ip6 filter forward ip6 daddr 2001::0/64 tcp dport 80 accept 13 | -------------------------------------------------------------------------------- /dpdk/firewall/etc/zones/ixia_tests.conf: -------------------------------------------------------------------------------- 1 | nft add rule filter forward ip saddr 192.168.1.0/24 ip daddr 192.168.0.0/24 accept 2 | 3 | nft add rule filer input accept 4 | 5 | -------------------------------------------------------------------------------- /dpdk/firewall/forward.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef FORWARD_H_ 31 | #define FORWARD_H_ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "util.h" 50 | #include "packet.h" 51 | #include "routing.h" 52 | 53 | #define uint32_to_char(ip, a, b, c, d) do {\ 54 | *a = (unsigned char)(ip >> 24 & 0xff);\ 55 | *b = (unsigned char)(ip >> 16 & 0xff);\ 56 | *c = (unsigned char)(ip >> 8 & 0xff);\ 57 | *d = (unsigned char)(ip & 0xff);\ 58 | } while (0) 59 | 60 | static inline 61 | __attribute__((always_inline)) 62 | void 63 | fwd_nic_pkt(struct rte_mbuf *m, struct worker_lc_cfg *lp) 64 | { 65 | uint32_t n_mbufs, burst; 66 | int ret; 67 | uint8_t port; 68 | 69 | if (likely(!(m->udata64 & PKT_META_ROUTED))) { 70 | struct ether_hdr *eh; 71 | struct ether_addr *ea; 72 | 73 | eh = rte_pktmbuf_mtod(m, struct ether_hdr *); 74 | if (unlikely(lp->rt.gws_ts != cfg.gws_ts)) { 75 | rt_refresh_gws(&lp->rt); 76 | } 77 | ea = rt_select_gw(m, eh, &lp->rt); 78 | /* Ensure that a valid gateway exists */ 79 | if (unlikely(ea == NULL)) { 80 | rte_pktmbuf_free(m); 81 | return; 82 | } 83 | 84 | ether_addr_copy(&eh->d_addr, &eh->s_addr); 85 | ether_addr_copy(ea, &eh->d_addr); 86 | } 87 | 88 | port = m->port; 89 | 90 | /* Request the NIC to place the vlan tag if required */ 91 | if (likely((m->udata64 & PKT_META_VLAN_TAG) == 0)) { 92 | m->ol_flags |= PKT_TX_VLAN_PKT; 93 | } 94 | burst = cfg.worker_write_burst_size; 95 | n_mbufs = lp->obuf[port].n_mbufs; 96 | lp->obuf[port].array[n_mbufs++] = m; 97 | if (n_mbufs < burst) { 98 | lp->obuf[port].n_mbufs = n_mbufs; 99 | lp->pending = 1; 100 | return; 101 | } 102 | ret = rte_ring_sp_enqueue_bulk( 103 | lp->orings[port], 104 | (void **)lp->obuf[port].array, 105 | burst); 106 | 107 | if (unlikely(ret == -ENOBUFS)) { 108 | util_free_mbufs_burst(lp->obuf[port].array, n_mbufs); 109 | } 110 | lp->obuf[port].n_mbufs = 0; 111 | lp->obuf_flush[port] = 0; 112 | 113 | } 114 | 115 | static inline 116 | __attribute__((always_inline)) 117 | void 118 | fwd_ring_pkt(struct rte_mbuf *m, struct worker_lc_cfg *lp, 119 | struct wrk_ring *ring) 120 | { 121 | uint32_t n_mbufs, burst; 122 | int ret; 123 | 124 | burst = cfg.worker_write_burst_size; 125 | n_mbufs = ring->obuf.n_mbufs; 126 | 127 | ring->obuf.array[n_mbufs++] = m; 128 | if (n_mbufs < burst) { 129 | ring->obuf.n_mbufs = n_mbufs; 130 | lp->pending = 1; 131 | return; 132 | } 133 | ret = rte_ring_sp_enqueue_bulk( 134 | ring->ring, 135 | (void **)ring->obuf.array, 136 | burst); 137 | 138 | if (unlikely(ret == -ENOBUFS)) { 139 | util_free_mbufs_burst(ring->obuf.array, n_mbufs); 140 | } 141 | ring->obuf.n_mbufs = 0; 142 | ring->obuf_flush = 0; 143 | } 144 | 145 | static inline 146 | __attribute__((always_inline)) 147 | void 148 | fwd_ctrl_pkt(struct rte_mbuf *m, struct worker_lc_cfg *lp) 149 | { 150 | int i; 151 | struct wrk_ring *ring; 152 | 153 | i = m->port % lp->n_crings; 154 | ring = &lp->crings[i]; 155 | 156 | #ifdef APP_STATS 157 | lp->crings_pkts[i]++; 158 | #endif 159 | 160 | return fwd_ring_pkt(m, lp, ring); 161 | } 162 | 163 | static inline 164 | __attribute__((always_inline)) 165 | void 166 | fwd_ol_pkt(struct rte_mbuf *m, struct worker_lc_cfg *lp) 167 | { 168 | struct wrk_ring *ring; 169 | 170 | ring = &lp->ol_rings[m->port % lp->n_ol_rings]; 171 | return fwd_ring_pkt(m, lp, ring); 172 | } 173 | 174 | static inline void 175 | flush_nic_buffers(struct worker_lc_cfg *lp) 176 | { 177 | uint32_t i; 178 | 179 | for (i = 0; i < MAX_NIC_PORTS; i++) { 180 | if (unlikely(lp->orings[i] == NULL)) { 181 | continue; 182 | } 183 | if (likely(lp->obuf_flush[i] == 0 || 184 | lp->obuf[i].n_mbufs == 0)) { 185 | lp->obuf_flush[i] = 1; 186 | lp->pending = lp->obuf[i].n_mbufs != 0; 187 | continue; 188 | } 189 | util_flush_sp_ring_buffer(lp->orings[i], &lp->obuf[i]); 190 | lp->obuf_flush[i] = 1; 191 | } 192 | } 193 | 194 | static inline void 195 | flush_ctrl_buffers(struct worker_lc_cfg *lp) 196 | { 197 | uint32_t n_crings, i; 198 | 199 | n_crings = lp->n_crings; 200 | for (i = 0; i < n_crings; i++) { 201 | struct wrk_ring *ring = &lp->crings[i]; 202 | 203 | if (likely(ring->obuf_flush == 0 || 204 | ring->obuf.n_mbufs == 0)) { 205 | ring->obuf_flush = 1; 206 | lp->pending = ring->obuf.n_mbufs != 0; 207 | continue; 208 | } 209 | util_flush_sp_ring_buffer(ring->ring, &ring->obuf); 210 | ring->obuf_flush = 1; 211 | } 212 | } 213 | 214 | static inline void 215 | flush_ol_buffers(struct worker_lc_cfg *lp) 216 | { 217 | uint32_t n_ol_rings, i; 218 | 219 | n_ol_rings = lp->n_ol_rings; 220 | for (i = 0; i < n_ol_rings; i++) { 221 | struct wrk_ring *ring = &lp->ol_rings[i]; 222 | 223 | if (likely(ring->obuf_flush == 0 || 224 | ring->obuf.n_mbufs == 0)) { 225 | ring->obuf_flush = 1; 226 | lp->pending = ring->obuf.n_mbufs != 0; 227 | continue; 228 | } 229 | util_flush_sp_ring_buffer(ring->ring, &ring->obuf); 230 | ring->obuf_flush = 1; 231 | } 232 | } 233 | 234 | #endif /* FORWARD_H_ */ 235 | -------------------------------------------------------------------------------- /dpdk/firewall/frag.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "main.h" 31 | #include "packet.h" 32 | #include "runtime.h" 33 | #include "frag.h" 34 | 35 | #define MAX_FLOW_NUM UINT16_MAX 36 | #define MIN_FLOW_NUM 1 37 | #define DEF_FLOW_NUM 0x1000 38 | 39 | /* TTL numbers are in ms */ 40 | #define MAX_FLOW_TTL (3600 * MS_PER_S) 41 | #define MIN_FLOW_TTL 1 42 | #define DEF_FLOW_TTL 5 * MS_PER_S 43 | 44 | #define MAX_FRAG_NUM RTE_LIBRTE_IP_FRAG_MAX_FRAG 45 | 46 | /* Should be a power of two */ 47 | #define IP_FRAG_TBL_BUCKET_ENTRIES 16 48 | 49 | int 50 | frag_init(struct frag_ctx *ctx, struct rte_mempool *pool, uint16_t flows, 51 | uint16_t ttl) 52 | { 53 | uint64_t frag_cycles; 54 | unsigned int socket; 55 | 56 | socket = rte_socket_id(); 57 | frag_cycles = (rte_get_tsc_hz() + MS_PER_S - 1) / MS_PER_S * ttl; 58 | 59 | ctx->tbl = rte_ip_frag_table_create( 60 | flows, 61 | IP_FRAG_TBL_BUCKET_ENTRIES, 62 | flows, 63 | frag_cycles, 64 | socket); 65 | if (ctx->tbl == NULL) { 66 | RTE_LOG(ERR, USER1, "Could not create fragment table!\n"); 67 | return -1; 68 | } 69 | ctx->pool = pool; 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /dpdk/firewall/frag.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef FRAG_H_ 31 | #define FRAG_H_ 32 | 33 | #include 34 | 35 | #include "main.h" 36 | 37 | struct frag_ctx { 38 | struct rte_ip_frag_tbl *tbl; 39 | struct rte_mempool *pool; 40 | struct rte_ip_frag_death_row death_row; 41 | }; 42 | 43 | int frag_init(struct frag_ctx *, struct rte_mempool *, uint16_t, uint16_t); 44 | 45 | static inline struct rte_mbuf * 46 | frag_ip_reass(struct frag_ctx *ctx, struct ipv4_hdr *ih, struct rte_mbuf *m) 47 | { 48 | struct rte_mbuf *mo; 49 | 50 | mo = rte_ipv4_frag_reassemble_packet(ctx->tbl, &ctx->death_row, m, 51 | now_tsc, ih); 52 | 53 | return mo; 54 | } 55 | 56 | static inline struct rte_mbuf * 57 | frag_ip6_reass(struct frag_ctx *ctx, struct rte_mbuf *m) 58 | { 59 | struct ether_hdr *eh; 60 | struct ipv6_hdr *ih; 61 | struct ipv6_extension_fragment *fh; 62 | struct rte_mbuf *mo; 63 | 64 | eh = rte_pktmbuf_mtod(m, struct ether_hdr *); 65 | ih = (struct ipv6_hdr *)(eh + 1); 66 | fh = rte_ipv6_frag_get_ipv6_fragment_header(ih); 67 | 68 | if (unlikely(fh == NULL)) { 69 | return NULL; 70 | } 71 | mo = rte_ipv6_frag_reassemble_packet(ctx->tbl, &ctx->death_row, m, 72 | now_tsc, ih, fh); 73 | 74 | return mo; 75 | } 76 | 77 | #endif /* FRAG_H_ */ 78 | -------------------------------------------------------------------------------- /dpdk/firewall/iface.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | #include "main.h" 52 | #include "util.h" 53 | #include "runtime.h" 54 | #include "packet.h" 55 | 56 | 57 | int 58 | scan_vlans(void) 59 | { 60 | struct ifaddrs *ifaddr, *ifa; 61 | uint16_t vlan; 62 | int family, n, changed; 63 | 64 | if (getifaddrs(&ifaddr) == -1) { 65 | RTE_LOG(DEBUG, USER1, "getifaddrs: %d\n", errno); 66 | return -1; 67 | } 68 | changed = 0; 69 | for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) { 70 | if (ifa->ifa_addr == NULL) { 71 | continue; 72 | } 73 | /* Only interested in vlan interfaces */ 74 | if (sscanf(ifa->ifa_name, "vlan%" SCNu16, &vlan) != 1) { 75 | continue; 76 | } 77 | family = ifa->ifa_addr->sa_family; 78 | if (family == AF_INET) { 79 | struct sockaddr_in *sa, *sm; 80 | in_addr_t addr, mask, net; 81 | 82 | sa = (struct sockaddr_in *)ifa->ifa_addr; 83 | sm = (struct sockaddr_in *)ifa->ifa_netmask; 84 | 85 | addr = sa->sin_addr.s_addr; 86 | mask = sm->sin_addr.s_addr; 87 | net = addr & mask; 88 | 89 | if (addr != cfg.vlans[vlan].ip.s_addr) { 90 | cfg.vlans[vlan].ip.s_addr = addr; 91 | } 92 | if (net != cfg.vlans[vlan].ip_net.s_addr) { 93 | changed = 1; 94 | cfg.vlans[vlan].ip_net.s_addr = net; 95 | cfg.vlans[vlan].ip_mask.s_addr = mask; 96 | } 97 | } else if (family == AF_INET6) { 98 | struct sockaddr_in6 *sa, *sm; 99 | __m128i addr, mask, net; 100 | 101 | sa = (struct sockaddr_in6 *)ifa->ifa_addr; 102 | sm = (struct sockaddr_in6 *)ifa->ifa_netmask; 103 | 104 | addr = _mm_loadu_si128((__m128i *) & sa->sin6_addr); 105 | mask = _mm_loadu_si128((__m128i *) & sm->sin6_addr); 106 | net = _mm_and_si128(addr, mask); 107 | 108 | if (!is_equal128(addr, cfg.vlans[vlan].ip6.xmm)) { 109 | _mm_store_si128(&cfg.vlans[vlan].ip6.xmm, addr); 110 | } 111 | if (!is_equal128(net, cfg.vlans[vlan].ip6_net.xmm)) { 112 | changed = 1; 113 | _mm_store_si128(&cfg.vlans[vlan].ip6_net.xmm, 114 | net); 115 | _mm_store_si128(&cfg.vlans[vlan].ip6_mask.xmm, 116 | mask); 117 | } 118 | } 119 | } 120 | freeifaddrs(ifaddr); 121 | 122 | return changed; 123 | } 124 | -------------------------------------------------------------------------------- /dpdk/firewall/init.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | 86 | #include "main.h" 87 | #include "util.h" 88 | 89 | struct rte_eth_conf port_conf = { 90 | .rxmode = { 91 | .mq_mode = ETH_MQ_RX_RSS, 92 | .max_rx_pkt_len = ETHER_MAX_LEN, 93 | .split_hdr_size = 0, 94 | .header_split = 0, /**< Header Split disabled */ 95 | .hw_ip_checksum = 1, /**< IP checksum offload enabled */ 96 | .hw_vlan_filter = 0, /**< VLAN filtering disabled */ 97 | .hw_vlan_strip = 1, /**< VLAN offload enabled */ 98 | .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ 99 | .hw_strip_crc = 0, /**< CRC stripped by hardware */ 100 | }, 101 | .rx_adv_conf = { 102 | .rss_conf = { 103 | .rss_key = NULL, 104 | .rss_hf = ETH_RSS_IP, 105 | }, 106 | }, 107 | .txmode = { 108 | .mq_mode = ETH_MQ_TX_NONE, 109 | }, 110 | }; 111 | 112 | static void 113 | init_mbuf_pools(void) 114 | { 115 | uint8_t socket, lcore; 116 | 117 | /* Init the buffer pools */ 118 | for (socket = 0; socket < MAX_SOCKETS; socket++) { 119 | char name[32]; 120 | if (cfg_is_socket_used(socket) == 0) { 121 | continue; 122 | } 123 | snprintf(name, sizeof(name), "mbuf_pool_%u", socket); 124 | RTE_LOG(DEBUG, USER1, "Creating the mbuf pool for socket %u.\n", 125 | socket); 126 | cfg.pools[socket] = rte_mempool_create( 127 | name, 128 | MEMPOOL_BUFFERS, 129 | MBUF_SIZE, 130 | MEMPOOL_CACHE_SIZE, 131 | sizeof(struct rte_pktmbuf_pool_private), 132 | rte_pktmbuf_pool_init, 133 | NULL, 134 | rte_pktmbuf_init, 135 | NULL, 136 | socket, 137 | 0); 138 | if (cfg.pools[socket] == NULL) { 139 | rte_panic("Cannot create mbuf pool on socket %u: %s\n", 140 | socket, strerror(rte_errno)); 141 | } 142 | } 143 | 144 | for (lcore = 0; lcore < MAX_LCORES; lcore++) { 145 | if (cfg.lcores[lcore].type == LCORE_TYPE_NONE) { 146 | continue; 147 | } 148 | socket = rte_lcore_to_socket_id(lcore); 149 | cfg.lcores[lcore].pool = cfg.pools[socket]; 150 | } 151 | } 152 | 153 | 154 | static void 155 | init_ol_mbuf_pools(void) 156 | { 157 | uint8_t socket; 158 | uint32_t nb_mbuf; 159 | 160 | /* 161 | * Allocate memory for packet reassembly At any given moment up to 162 | * mbufs could be stored in the 163 | * fragment table. 164 | */ 165 | nb_mbuf = 166 | RTE_MAX(cfg.frag_max_flow_num, 2 * cfg.io_rx_read_burst_size) * 167 | MAX_FRAG_NUM; 168 | nb_mbuf *= (port_conf.rxmode.max_rx_pkt_len + BUF_SIZE - 1) / BUF_SIZE; 169 | nb_mbuf *= 2; /* IPv4 and IPv6 */ 170 | nb_mbuf = RTE_MAX(nb_mbuf, (uint32_t)MEMPOOL_BUFFERS); 171 | 172 | for (socket = 0; socket < MAX_SOCKETS; socket++) { 173 | char name[32]; 174 | if (cfg_is_socket_used(socket) == 0) { 175 | continue; 176 | } 177 | snprintf(name, sizeof(name), "mbuf_ol_pool_%u", socket); 178 | RTE_LOG(DEBUG, 179 | USER1, 180 | "Creating the mbuf offload pool for socket %u.\n", 181 | socket); 182 | cfg.ol_pools[socket] = rte_mempool_create( 183 | name, 184 | nb_mbuf, 185 | MBUF_SIZE, 186 | MEMPOOL_CACHE_SIZE, 187 | sizeof(struct rte_pktmbuf_pool_private), 188 | rte_pktmbuf_pool_init, 189 | NULL, 190 | rte_pktmbuf_init, 191 | NULL, 192 | socket, 193 | 0); 194 | if (cfg.pools[socket] == NULL) { 195 | rte_panic("Cannot create mbuf pool on socket %u: %s\n", 196 | socket, strerror(rte_errno)); 197 | } 198 | } 199 | } 200 | 201 | static void 202 | init_rings_rx(void) 203 | { 204 | uint8_t iolc, wlc = 0; 205 | 206 | /* Initialize the rings for the RX side */ 207 | for (iolc = 0; iolc < MAX_LCORES; iolc++) { 208 | struct lc_cfg *lcp = &cfg.lcores[iolc]; 209 | unsigned socket_io; 210 | 211 | if (lcp->type != LCORE_TYPE_IO || lcp->io.rx.n_nic_queues == 0) { 212 | continue; 213 | } 214 | socket_io = rte_lcore_to_socket_id(iolc); 215 | 216 | for (wlc = 0; wlc < MAX_LCORES; wlc++) { 217 | char name[32]; 218 | struct lc_cfg *wlcp = &cfg.lcores[wlc]; 219 | struct rte_ring *ring = NULL; 220 | 221 | if (wlcp->type != LCORE_TYPE_WORKER) { 222 | continue; 223 | } 224 | if ((lcp->io.rx.workers_mask & (1 << wlcp->worker.id)) 225 | == 0) { 226 | continue; 227 | } 228 | RTE_LOG(DEBUG, USER1, "Creating ring to connect IO RX" 229 | "lcore %u (socket %u)-> worker %u (lcore %u)...\n", 230 | iolc, socket_io, wlcp->worker.id, wlc); 231 | snprintf(name, sizeof(name), "ring_rx_s%u_io%u_w%u", 232 | socket_io, iolc, wlcp->worker.id); 233 | ring = rte_ring_create( 234 | name, 235 | cfg.ring_rx_size, 236 | socket_io, 237 | RING_F_SP_ENQ | RING_F_SC_DEQ); 238 | if (ring == NULL) { 239 | rte_panic("Cannot create ring to connect RX IO " 240 | "lcore %u with worker core %u\n", 241 | iolc, 242 | wlcp->worker.id); 243 | } 244 | lcp->io.rx.rings[lcp->io.rx.n_rings] = ring; 245 | lcp->io.rx.n_rings++; 246 | wlcp->worker.irings[wlcp->worker.n_irings] = ring; 247 | wlcp->worker.n_irings++; 248 | } 249 | } 250 | 251 | /* 252 | * We should perform some sanity checks here. E.g., to determine if 253 | * the pipeline is being correctly assembled. 254 | */ 255 | } 256 | 257 | static void 258 | init_rings_tx(void) 259 | { 260 | unsigned lcore; 261 | 262 | /* Initialize the rings for the TX side */ 263 | for (lcore = 0; lcore < MAX_LCORES; lcore++) { 264 | struct lc_cfg *wlcp = &cfg.lcores[lcore]; 265 | uint8_t port; 266 | 267 | RTE_LOG(DEBUG, USER1, "Checking lcore %u, type: %u\n", lcore, wlcp->type); 268 | if (wlcp->type != LCORE_TYPE_WORKER) { 269 | continue; 270 | } 271 | for (port = 0; port < MAX_NIC_PORTS; port++) { 272 | char name[32]; 273 | struct io_lc_cfg *iolcp = NULL; 274 | struct rte_ring *ring; 275 | uint32_t socket, iolc; 276 | 277 | if (!(cfg.ifaces[port].flags & NIC_FLAG_TX_ON)) { 278 | continue; 279 | } 280 | if (cfg_lcore_for_nic_tx((uint8_t)port, &iolc) < 0) { 281 | rte_panic( 282 | "Init error: %u has no TX core.\n", port); 283 | } 284 | iolcp = &cfg.lcores[iolc].io; 285 | socket = rte_lcore_to_socket_id(iolc); 286 | 287 | RTE_LOG(DEBUG, USER1, 288 | "Creating ring to connect worker %u (lcore %u) " 289 | "to TX port %u (using io lcore %u, socket: %u).\n", 290 | wlcp->worker.id, lcore, port, (unsigned)iolc, 291 | (unsigned)socket); 292 | 293 | snprintf(name, sizeof(name), "ring_tx_s%u_w%u_p%u", 294 | socket, lcore, port); 295 | ring = rte_ring_create( 296 | name, 297 | cfg.ring_tx_size, 298 | socket, 299 | RING_F_SP_ENQ | RING_F_SC_DEQ); 300 | if (ring == NULL) { 301 | rte_panic("Cannot create ring to connect " 302 | "worker core %u with TX port %u\n", 303 | lcore, 304 | port); 305 | } 306 | wlcp->worker.orings[port] = ring; 307 | iolcp->tx.rings[port][wlcp->worker.id] = ring; 308 | iolcp->tx.workers_mask |= 1 << wlcp->worker.id; 309 | } 310 | } 311 | 312 | for (lcore = 0; lcore < MAX_LCORES; lcore++) { 313 | struct lc_cfg *lcp = &cfg.lcores[lcore]; 314 | unsigned i; 315 | 316 | if (lcp->type != LCORE_TYPE_IO || lcp->io.tx.n_nic_ports == 0) { 317 | continue; 318 | } 319 | for (i = 0; i < lcp->io.tx.n_nic_ports; i++) { 320 | unsigned port, j; 321 | port = lcp->io.tx.nic_ports[i]; 322 | for (j = 0; j < cfg_lcores_worker(); j++) { 323 | if (lcp->io.tx.rings[port][j] == NULL) { 324 | rte_panic("Init error (io TX rings)\n"); 325 | } 326 | } 327 | } 328 | } 329 | } 330 | 331 | 332 | static void 333 | init_rings_ctrl(void) 334 | { 335 | uint32_t wtype; 336 | uint8_t ctrl_lc, wrklc; 337 | 338 | wrklc = 0; 339 | wtype = WORKER_TYPE_CTRL_KNI | WORKER_TYPE_CTRL_TAP; 340 | 341 | /* Initialize the control plane rings */ 342 | for (ctrl_lc = 0; ctrl_lc < MAX_LCORES; ctrl_lc++) { 343 | struct lc_cfg *lcp = &cfg.lcores[ctrl_lc]; 344 | 345 | if (lcp->type != LCORE_TYPE_WORKER || 346 | (lcp->worker.type & wtype) == 0) { 347 | continue; 348 | } 349 | /* Link control path clients to control path providers */ 350 | for (wrklc = 0; wrklc < MAX_LCORES; wrklc++) { 351 | char name[32]; 352 | struct worker_lc_cfg *wlcp = NULL; 353 | struct rte_ring *ring; 354 | unsigned w_socket; 355 | 356 | if (cfg.lcores[wrklc].type != LCORE_TYPE_WORKER || 357 | !cfg.lcores[wrklc].worker.ctrlplane) { 358 | continue; 359 | } 360 | wlcp = &cfg.lcores[wrklc].worker; 361 | w_socket = rte_lcore_to_socket_id(wrklc); 362 | 363 | RTE_LOG(DEBUG, USER1, "Creating ring to worker " 364 | "lcore %u (socket %u) -> control lcore %u ...\n", 365 | wrklc, 366 | w_socket, 367 | ctrl_lc); 368 | snprintf(name, sizeof(name), "ring_ws%u_ctrl%u_w%u", 369 | w_socket, 370 | ctrl_lc, 371 | wrklc); 372 | ring = rte_ring_create( 373 | name, 374 | cfg.ring_rx_size, 375 | w_socket, 376 | RING_F_SP_ENQ | RING_F_SC_DEQ); 377 | if (ring == NULL) { 378 | rte_panic("Cannot create ring to connect worker " 379 | "lcore %u with control core %u\n", 380 | wrklc, 381 | ctrl_lc); 382 | } 383 | wlcp->crings[wlcp->n_crings++].ring = ring; 384 | lcp->worker.irings[lcp->worker.n_irings++] = ring; 385 | } 386 | } 387 | 388 | /* 389 | * TODO: We should perform some sanity checks here. E.g., to 390 | * determine if the pipeline is being correctly assembled. 391 | */ 392 | } 393 | 394 | static void 395 | init_rings_offload(void) 396 | { 397 | uint8_t olcli, olsrv = 0; 398 | 399 | /* Initialize the offload worker rings */ 400 | for (olsrv = 0; olsrv < MAX_LCORES; olsrv++) { 401 | struct lc_cfg *srv = &cfg.lcores[olsrv]; 402 | 403 | if (srv->type != LCORE_TYPE_WORKER || 404 | srv->worker.type != WORKER_TYPE_FW || 405 | srv->worker.ol != WORKER_OL_PROV) { 406 | continue; 407 | } 408 | /* Link offload clients with offload servers */ 409 | for (olcli = 0; olcli < MAX_LCORES; olcli++) { 410 | char name[32]; 411 | struct worker_lc_cfg *cli = NULL; 412 | struct rte_ring *ring; 413 | unsigned wsocket; 414 | 415 | if (cfg.lcores[olcli].type != LCORE_TYPE_WORKER || 416 | cfg.lcores[olcli].worker.ol != WORKER_OL_CLNT) { 417 | continue; 418 | } 419 | cli = &cfg.lcores[olcli].worker; 420 | wsocket = rte_lcore_to_socket_id(olcli); 421 | 422 | RTE_LOG(DEBUG, USER1, "Creating ring to worker offload " 423 | "client core %u (socket %u) -> offload server core " 424 | "%u ...\n", 425 | olcli, 426 | wsocket, 427 | olsrv); 428 | snprintf(name, sizeof(name), 429 | "ring_s%u_olcli%u_olsrv%u", wsocket, olcli, olsrv); 430 | ring = rte_ring_create( 431 | name, 432 | cfg.ring_rx_size, 433 | wsocket, 434 | RING_F_SP_ENQ | RING_F_SC_DEQ); 435 | if (ring == NULL) { 436 | rte_panic("Cannot create ring to connect worker " 437 | "offload lcore %u with offload core %u\n", 438 | olcli, olsrv); 439 | } 440 | srv->worker.irings[srv->worker.n_irings++] = ring; 441 | cli->ol_rings[cli->n_ol_rings++].ring = ring; 442 | } 443 | } 444 | 445 | /* 446 | * We should perform some sanity checks here. E.g., to determine if 447 | * the pipeline is being correctly assembled. 448 | */ 449 | } 450 | 451 | static void 452 | print_link_status(uint8_t port, struct rte_eth_link *link) 453 | { 454 | if (link->link_status) { 455 | RTE_LOG(DEBUG, USER1, "Port %d Link Up - speed %u Mbps - %s\n", 456 | port, (unsigned)link->link_speed, 457 | (link->link_duplex == ETH_LINK_FULL_DUPLEX) ? 458 | ("full-duplex") : ("half-duplex\n")); 459 | } else { 460 | RTE_LOG(DEBUG, USER1, "Port %d Link Down\n", port); 461 | } 462 | } 463 | 464 | /* Check the link status of all ports, wait up to 9 seconds, and print them */ 465 | static void 466 | check_all_ports_link_status(uint8_t port_num, uint32_t port_mask) 467 | { 468 | #define CHECK_INTERVAL 100 /* 100ms */ 469 | #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ 470 | struct rte_eth_link link; 471 | uint32_t n_rx_queues; 472 | uint8_t port, count, all_ports_up, print_flag = 0; 473 | 474 | RTE_LOG(DEBUG, USER1, "\nChecking link status"); 475 | fflush(stdout); 476 | for (count = 0; count <= MAX_CHECK_TIME; count++) { 477 | all_ports_up = 1; 478 | for (port = 0; port < port_num; port++) { 479 | if ((port_mask & (1 << port)) == 0) 480 | continue; 481 | 482 | n_rx_queues = cfg_nic_rx_queues_per_port(port); 483 | 484 | if (n_rx_queues == 0 && 485 | !(cfg.ifaces[port].flags & NIC_FLAG_TX_ON)) { 486 | continue; 487 | } 488 | memset(&link, 0, sizeof(link)); 489 | rte_eth_link_get_nowait(port, &link); 490 | /* print link status if flag set */ 491 | if (print_flag == 1) { 492 | print_link_status(port, &link); 493 | continue; 494 | } 495 | /* clear all_ports_up flag if any link down */ 496 | if (link.link_status == 0) { 497 | all_ports_up = 0; 498 | break; 499 | } 500 | } 501 | /* after finally printing all link status, get out */ 502 | if (print_flag == 1) 503 | break; 504 | 505 | if (all_ports_up == 0) { 506 | printf("."); 507 | fflush(stdout); 508 | rte_delay_ms(CHECK_INTERVAL); 509 | } 510 | /* set the print_flag if all ports up or timeout */ 511 | if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { 512 | print_flag = 1; 513 | printf("done\n"); 514 | } 515 | } 516 | } 517 | 518 | static int 519 | init_bond_slaves(uint8_t port) 520 | { 521 | struct rte_eth_dev_info dev_info; 522 | struct rte_eth_txconf *txconf; 523 | struct rte_mempool *pool; 524 | uint32_t n_slaves, lcore; 525 | unsigned int socket; 526 | int ret; 527 | uint8_t slave; 528 | 529 | n_slaves = cfg.ifaces[port].n_slaves; 530 | cfg_lcore_for_nic_tx(port, &lcore); 531 | socket = rte_lcore_to_socket_id(lcore); 532 | pool = cfg.lcores[lcore].pool; 533 | 534 | for (slave = 0; slave < n_slaves; slave++) { 535 | /* Init port */ 536 | RTE_LOG(DEBUG, USER1, "Initializing slave %d...\n", slave); 537 | ret = rte_eth_dev_configure(slave, 1, 1, &port_conf); 538 | if (ret < 0) { 539 | rte_panic("Slave %d config error (%d)\n", slave, ret); 540 | } 541 | /* Initialize RX queue */ 542 | RTE_LOG(DEBUG, USER1, "Initializing slave %d RX queue %d ...\n", 543 | slave, 0); 544 | ret = rte_eth_rx_queue_setup(slave, 0, cfg.nic_rx_ring_size, 545 | socket, NULL, pool); 546 | if (ret < 0) { 547 | rte_panic("Cannot init RX queue %d on slave %d (%d)\n", 548 | 0, slave, ret); 549 | } 550 | /* Initialize TX queue */ 551 | RTE_LOG(DEBUG, USER1, "Initializing slave %d TX queue 0...\n", 552 | slave); 553 | 554 | rte_eth_dev_info_get(slave, &dev_info); 555 | txconf = &dev_info.default_txconf; 556 | 557 | /* Enable VLAN offloading */ 558 | txconf->txq_flags &= ~ETH_TXQ_FLAGS_NOVLANOFFL; 559 | ret = rte_eth_tx_queue_setup( 560 | slave, 561 | 0, 562 | cfg.nic_tx_ring_size, 563 | socket, 564 | txconf); 565 | 566 | if (ret < 0) { 567 | rte_panic("Cannot init TX queue 0 on slave %d (%d)\n", 568 | slave, ret); 569 | } 570 | /* Start the port */ 571 | ret = rte_eth_dev_start(slave); 572 | if (ret < 0) { 573 | rte_panic("Cannot start slave %d (%d)\n", slave, ret); 574 | } 575 | rte_eth_macaddr_get(slave, &cfg.ifaces[slave].hwaddr); 576 | } 577 | 578 | return 1; 579 | } 580 | 581 | static void 582 | init_ifaces(void) 583 | { 584 | struct rte_eth_dev_info dev_info; 585 | struct rte_eth_txconf *txconf; 586 | uint32_t lcore; 587 | unsigned socket; 588 | int ret; 589 | uint16_t queue, n_rx_queues; 590 | uint8_t port; 591 | 592 | /* Init NIC ports and queues, then start the ports */ 593 | for (port = 0; port < MAX_NIC_PORTS; port++) { 594 | struct rte_mempool *pool; 595 | 596 | n_rx_queues = cfg_nic_rx_queues_per_port(port); 597 | if ((n_rx_queues == 0 && 598 | !(cfg.ifaces[port].flags & NIC_FLAG_TX_ON)) || 599 | (cfg.ifaces[port].flags & NIC_FLAG_BOND_SLAVE)) { 600 | continue; 601 | } 602 | if (cfg.ifaces[port].flags & NIC_FLAG_BOND_IFACE) { 603 | char name[MAX_NIC_LEN]; 604 | int r; 605 | 606 | snprintf(name, sizeof(name), "bond%d", port); 607 | r = rte_eth_bond_create( 608 | name, 609 | BONDING_MODE_8023AD, 610 | 0); 611 | 612 | if (r != port) { 613 | rte_panic("bond id != port. Deal with this.\n"); 614 | } 615 | if (!init_bond_slaves(port)) { 616 | rte_panic("Could not init bond slaves for %d.\n", 617 | port); 618 | } 619 | } 620 | /* Init port */ 621 | RTE_LOG(DEBUG, USER1, "Initializing NIC port %d...\n", port); 622 | ret = rte_eth_dev_configure( 623 | port, 624 | n_rx_queues, 625 | 1, 626 | &port_conf); 627 | 628 | if (ret < 0) { 629 | rte_panic("Cannot init NIC port %d (%d)\n", port, ret); 630 | } 631 | /* Init RX queues */ 632 | for (queue = 0; queue < MAX_RX_QUEUES_PER_NIC_PORT; queue++) { 633 | if (cfg.ifaces[port].rx_queues[queue] == 0) { 634 | continue; 635 | } 636 | cfg_lcore_for_nic_rx(port, queue, &lcore); 637 | socket = rte_lcore_to_socket_id(lcore); 638 | pool = cfg.lcores[lcore].pool; 639 | 640 | RTE_LOG(DEBUG, USER1, 641 | "Initializing NIC port %d RX queue %d ...\n", 642 | port, queue); 643 | ret = rte_eth_rx_queue_setup( 644 | port, 645 | queue, 646 | cfg.nic_rx_ring_size, 647 | socket, 648 | NULL, 649 | pool); 650 | if (ret < 0) { 651 | rte_panic( 652 | "Cannot init RX queue %d on port %d (%d)\n", 653 | queue, port, ret); 654 | } 655 | } 656 | 657 | /* Init TX queues */ 658 | rte_eth_dev_info_get(port, &dev_info); 659 | txconf = &dev_info.default_txconf; 660 | 661 | /* Enable VLAN offloading */ 662 | txconf->txq_flags &= ~ETH_TXQ_FLAGS_NOVLANOFFL; 663 | 664 | if (cfg.ifaces[port].flags & NIC_FLAG_TX_ON) { 665 | cfg_lcore_for_nic_tx(port, &lcore); 666 | socket = rte_lcore_to_socket_id(lcore); 667 | RTE_LOG(DEBUG, USER1, 668 | "Initializing NIC port %u TX queue 0...\n", 669 | (unsigned)port); 670 | ret = rte_eth_tx_queue_setup( 671 | port, 672 | 0, 673 | (uint16_t)cfg.nic_tx_ring_size, 674 | socket, 675 | txconf); 676 | if (ret < 0) { 677 | rte_panic( 678 | "Cannot init TX queue 0 on port %d (%d)\n", 679 | port, ret); 680 | } 681 | } 682 | /* Add slave interfaces to bond */ 683 | if (cfg.ifaces[port].flags & NIC_FLAG_BOND_IFACE) { 684 | int i; 685 | 686 | for (i = 0; i < cfg.ifaces[port].n_slaves; i++) { 687 | int r; 688 | RTE_LOG(DEBUG, USER1, 689 | "Adding port %d to bond %d.\n", 690 | i, port); 691 | r = rte_eth_bond_slave_add( 692 | port, 693 | cfg.ifaces[port].slaves[i]); 694 | if (r == -1) { 695 | rte_panic("Could not add slave %d.\n", 696 | i); 697 | } 698 | } 699 | //rte_eth_promiscuous_enable(port); 700 | } 701 | /* Start port */ 702 | ret = rte_eth_dev_start(port); 703 | if (ret < 0) { 704 | rte_panic("Cannot start port %d (%d)\n", port, ret); 705 | } 706 | rte_eth_macaddr_get(port, &cfg.ifaces[port].hwaddr); 707 | //rte_eth_promiscuous_enable(port); 708 | } 709 | 710 | check_all_ports_link_status(MAX_NIC_PORTS, (~0x0)); 711 | } 712 | 713 | static void 714 | init_tap(void) 715 | { 716 | #ifndef IFNAMSIZ 717 | #define IFNAMSIZ 32 718 | #endif 719 | char tapname[IFNAMSIZ]; 720 | struct lc_cfg *lcp; 721 | uint8_t lcore, tap; 722 | 723 | for (lcore = 0; lcore < MAX_LCORES; lcore++) { 724 | struct tap_lc_cfg *taplcp; 725 | 726 | lcp = &cfg.lcores[lcore]; 727 | if (lcp->type != LCORE_TYPE_WORKER || 728 | lcp->worker.type != WORKER_TYPE_CTRL_TAP) { 729 | continue; 730 | } 731 | taplcp = &lcp->worker.tap; 732 | 733 | for (tap = 0; tap < taplcp->n_taps; tap++) { 734 | int8_t port; 735 | int tapfd, i; 736 | 737 | if ((port = taplcp->tap_to_port[tap]) == -1) { 738 | continue; 739 | } 740 | snprintf(tapname, sizeof(tapname), "mitra%u", tap); 741 | tapfd = tap_create(tapname, &cfg.ifaces[port]); 742 | if (tapfd < 0) { 743 | rte_panic("Could not create interface: %s.\n", 744 | tapname); 745 | } 746 | taplcp->taps[tap] = tapfd; 747 | 748 | for (i = 0; taplcp->port_to_tap[i] >= 0; i++) { 749 | taplcp->port_to_tap[i] = 750 | taplcp->taps[taplcp->port_to_tap[i]]; 751 | } 752 | } 753 | } 754 | } 755 | 756 | static void 757 | init_kni(void) 758 | { 759 | struct lc_cfg *lcp; 760 | struct rte_kni *kni; 761 | uint8_t lcore, i; 762 | 763 | if (cfg.n_kni_ports == 0) { 764 | RTE_LOG(DEBUG, USER1, 765 | "No KNI ports configured. Skipping KNI init.\n"); 766 | return; 767 | } 768 | rte_kni_init(cfg.n_kni_ports); 769 | for (lcore = 0; lcore < MAX_LCORES; lcore++) { 770 | struct kni_lc_cfg *knilcp; 771 | 772 | lcp = &cfg.lcores[lcore]; 773 | if (lcp->type != LCORE_TYPE_WORKER || 774 | lcp->worker.type != WORKER_TYPE_CTRL_KNI) { 775 | continue; 776 | } 777 | knilcp = &lcp->worker.kni; 778 | for (i = 0; i < knilcp->n_kni; i++) { 779 | int8_t port; 780 | 781 | if ((port = knilcp->kni_to_port[i]) == -1) { 782 | continue; 783 | } 784 | kni = kni_alloc_port(port, lcp); 785 | if (kni == NULL) { 786 | rte_exit(EXIT_FAILURE, 787 | "Error creating KNI for port: %d\n", port); 788 | } 789 | knilcp->kni[i] = kni; 790 | } 791 | } 792 | } 793 | 794 | static void 795 | init_fw(void) 796 | { 797 | if (fw_init() != 0) { 798 | rte_exit(EXIT_FAILURE, 799 | "Could not initialize firewall workers.\n"); 800 | } 801 | } 802 | 803 | static void 804 | init_offload(void) 805 | { 806 | 807 | } 808 | 809 | void 810 | init_app(void) 811 | { 812 | init_mbuf_pools(); 813 | init_ol_mbuf_pools(); 814 | init_rings_rx(); 815 | init_rings_tx(); 816 | init_rings_ctrl(); 817 | init_rings_offload(); 818 | init_ifaces(); 819 | init_tap(); 820 | init_kni(); 821 | init_fw(); 822 | init_offload(); 823 | 824 | RTE_LOG(DEBUG, USER1, "Initialization complete.\n"); 825 | } 826 | -------------------------------------------------------------------------------- /dpdk/firewall/io.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "main.h" 50 | #include "util.h" 51 | #include "runtime.h" 52 | #include "packet.h" 53 | 54 | #define FLUSH_TX_PORT(lp, port) \ 55 | do { \ 56 | n_pkts = rte_eth_tx_burst( \ 57 | port, \ 58 | 0, \ 59 | lp->tx.obuf[port].array, \ 60 | (uint16_t)lp->tx.obuf[port].n_mbufs); \ 61 | \ 62 | if (unlikely(n_pkts < lp->tx.obuf[port].n_mbufs)) { \ 63 | util_free_mbufs_burst( \ 64 | lp->tx.obuf[port].array + n_pkts, \ 65 | lp->tx.obuf[port].n_mbufs - n_pkts);\ 66 | } \ 67 | lp->tx.obuf[port].n_mbufs = 0; \ 68 | lp->tx.obuf_flush[port] = 1; \ 69 | cfg.ifaces[port].lacp = 0; \ 70 | } while (0) 71 | 72 | static inline 73 | __attribute__((always_inline)) 74 | void 75 | send_pkts_to_worker(struct io_lc_cfg *lp, uint32_t worker, 76 | struct rte_mbuf *m, uint32_t burst) 77 | { 78 | uint32_t n_mbufs; 79 | int ret; 80 | 81 | /* Reset packet */ 82 | PKT_INIT(m); 83 | 84 | n_mbufs = lp->rx.obuf[worker].n_mbufs; 85 | lp->rx.obuf[worker].array[n_mbufs++] = m; 86 | if (n_mbufs < burst) { 87 | lp->rx.obuf[worker].n_mbufs = n_mbufs; 88 | lp->pending = 1; 89 | return; 90 | } 91 | ret = rte_ring_sp_enqueue_bulk( 92 | lp->rx.rings[worker], 93 | (void **)lp->rx.obuf[worker].array, 94 | n_mbufs); 95 | 96 | if (unlikely(ret == -ENOBUFS)) { 97 | util_free_mbufs_burst(lp->rx.obuf[worker].array, n_mbufs); 98 | RTE_LOG(WARNING, USER1, 99 | "Could not enqueue %u packets to worker %u!\n", 100 | n_mbufs, worker); 101 | } 102 | #if APP_STATS 103 | else { 104 | lp->rx.rings_pkts[worker] += n_mbufs; 105 | } 106 | #endif 107 | 108 | lp->rx.obuf[worker].n_mbufs = 0; 109 | lp->rx.obuf_flush[worker] = 0; 110 | 111 | } 112 | 113 | static inline uint8_t 114 | rx_nic_pkts(struct io_lc_cfg *lp, uint32_t n_workers, 115 | uint32_t r_burst, uint32_t w_burst) 116 | { 117 | struct rte_mbuf *m10, *m11, *m20, *m21; 118 | uint32_t i; 119 | uint8_t is_active; 120 | 121 | is_active = 0; 122 | for (i = 0; i < lp->rx.n_nic_queues; i++) { 123 | uint8_t port = lp->rx.nic_queues[i].port; 124 | uint16_t queue = lp->rx.nic_queues[i].queue; 125 | uint32_t n_rx, j; 126 | 127 | n_rx = rte_eth_rx_burst( 128 | port, 129 | queue, 130 | lp->rx.ibuf.array, 131 | (uint16_t)r_burst); 132 | 133 | if (unlikely(n_rx == 0)) { 134 | continue; 135 | } 136 | is_active = 1; 137 | 138 | #if APP_STATS 139 | lp->rx.nic_q_pkts[i] += n_rx; 140 | #endif 141 | m10 = lp->rx.ibuf.array[0]; 142 | m11 = lp->rx.ibuf.array[1]; 143 | m20 = lp->rx.ibuf.array[2]; 144 | m21 = lp->rx.ibuf.array[3]; 145 | 146 | IO_RX_PREFETCH0(m20); 147 | IO_RX_PREFETCH0(m21); 148 | 149 | for (j = 0; j + 3 < n_rx; j += 2) { 150 | struct rte_mbuf *m00, *m01; 151 | uint32_t worker0, worker1; 152 | 153 | m00 = m10; 154 | m01 = m11; 155 | 156 | m10 = m20; 157 | m11 = m21; 158 | 159 | /* Length of ibuf.array must be > r_burst + 5 */ 160 | m20 = lp->rx.ibuf.array[j + 4]; 161 | m21 = lp->rx.ibuf.array[j + 5]; 162 | IO_RX_PREFETCH0(m20); 163 | IO_RX_PREFETCH0(m21); 164 | 165 | worker0 = m00->port & (n_workers - 1); 166 | worker1 = m01->port & (n_workers - 1); 167 | send_pkts_to_worker(lp, worker0, m00, w_burst); 168 | send_pkts_to_worker(lp, worker1, m01, w_burst); 169 | } 170 | 171 | /* 172 | * Handle the last 1, 2 (when n_rx is even) or 3 (when n_rx 173 | * is odd) packets 174 | */ 175 | for (; j < n_rx; j++) { 176 | struct rte_mbuf *m; 177 | uint32_t worker; 178 | 179 | m = m10; 180 | m10 = m11; 181 | m11 = m20; 182 | m20 = m21; 183 | 184 | IO_RX_PREFETCH0(m10); 185 | 186 | worker = m->port & (n_workers - 1); 187 | send_pkts_to_worker(lp, worker, m, w_burst); 188 | } 189 | } 190 | 191 | return is_active; 192 | } 193 | 194 | static inline void 195 | flush_rx_buffers(struct io_lc_cfg *lp, uint32_t n_workers) 196 | { 197 | uint32_t worker; 198 | 199 | for (worker = 0; worker < n_workers; worker++) { 200 | int ret; 201 | 202 | if (likely((lp->rx.obuf_flush[worker] == 0) || 203 | (lp->rx.obuf[worker].n_mbufs == 0))) { 204 | lp->rx.obuf_flush[worker] = 1; 205 | continue; 206 | } 207 | ret = rte_ring_sp_enqueue_bulk( 208 | lp->rx.rings[worker], 209 | (void **)lp->rx.obuf[worker].array, 210 | lp->rx.obuf[worker].n_mbufs); 211 | 212 | if (unlikely(ret < 0)) { 213 | util_free_mbufs_burst(lp->rx.obuf[worker].array, 214 | lp->rx.obuf[worker].n_mbufs); 215 | } 216 | lp->rx.obuf[worker].n_mbufs = 0; 217 | lp->rx.obuf_flush[worker] = 1; 218 | } 219 | } 220 | 221 | static inline uint8_t 222 | tx_nic_pkts(struct io_lc_cfg *lp, uint32_t n_workers, 223 | uint32_t r_burst, uint32_t w_burst) 224 | { 225 | uint32_t i, worker; 226 | uint8_t is_active; 227 | 228 | is_active = 0; 229 | for (i = 0; i < lp->tx.n_nic_ports; i++) { 230 | uint8_t port = lp->tx.nic_ports[i]; 231 | 232 | for (worker = 0; worker < n_workers; worker++) { 233 | uint32_t n_mbufs, n_pkts; 234 | 235 | struct rte_ring *ring = lp->tx.rings[port][worker]; 236 | 237 | n_mbufs = lp->tx.obuf[port].n_mbufs; 238 | n_pkts = rte_ring_sc_dequeue_burst( 239 | ring, 240 | (void **)&lp->tx.obuf[port].array[n_mbufs], 241 | r_burst); 242 | 243 | if (unlikely(n_pkts == 0)) { 244 | continue; 245 | } 246 | is_active = 1; 247 | n_mbufs += n_pkts; 248 | 249 | if (n_mbufs < w_burst) { 250 | lp->pending = 1; 251 | lp->tx.obuf[port].n_mbufs = n_mbufs; 252 | continue; 253 | } 254 | n_pkts = rte_eth_tx_burst( 255 | port, 256 | 0, 257 | lp->tx.obuf[port].array, 258 | (uint16_t)n_mbufs); 259 | #if APP_STATS 260 | lp->tx.nic_pkts[port] += n_pkts; 261 | #endif 262 | 263 | if (n_pkts < n_mbufs) { 264 | util_free_mbufs_burst( 265 | lp->tx.obuf[port].array + n_pkts, 266 | n_mbufs - n_pkts); 267 | } 268 | lp->tx.obuf[port].n_mbufs = 0; 269 | lp->tx.obuf_flush[port] = 0; 270 | cfg.ifaces[port].lacp = 0; 271 | } 272 | if (cfg.ifaces[port].lacp) { 273 | uint32_t n_pkts = 0; 274 | 275 | FLUSH_TX_PORT(lp, port); 276 | #ifdef APP_STATS 277 | lp->tx.nic_pkts[port] += n_pkts; 278 | #endif 279 | } 280 | } 281 | 282 | return is_active; 283 | } 284 | 285 | static inline void 286 | flush_tx_buffers(struct io_lc_cfg *lp) 287 | { 288 | uint8_t i; 289 | 290 | for (i = 0; i < lp->tx.n_nic_ports; i++) { 291 | uint32_t n_pkts; 292 | uint8_t port; 293 | 294 | n_pkts = 0; 295 | port = lp->tx.nic_ports[i]; 296 | 297 | if (likely((lp->tx.obuf_flush[port] == 0) || 298 | (lp->tx.obuf[port].n_mbufs == 0))) { 299 | lp->tx.obuf_flush[port] = 1; 300 | continue; 301 | } 302 | FLUSH_TX_PORT(lp, port); 303 | 304 | LOG(DEBUG, USER1, "[TX] Sent %u packets\n", n_pkts); 305 | 306 | #ifdef APP_STATS 307 | lp->tx.nic_pkts[port] += n_pkts; 308 | #endif 309 | } 310 | } 311 | 312 | static void 313 | rx_stats(struct io_lc_cfg *lp, uint64_t now) 314 | { 315 | uint32_t i; 316 | 317 | for (i = 0; i < lp->rx.n_nic_queues; i++) { 318 | uint64_t pps; 319 | 320 | if (lp->rx.nic_q_pkts[0] == 0) { 321 | continue; 322 | } 323 | pps = lp->rx.nic_q_pkts[i] / 324 | (TSC2US(now - lp->stats_tsc) / US_PER_S); 325 | lp->rx.nic_q_pkts[i] = 0; 326 | 327 | RTE_LOG( 328 | DEBUG, 329 | USER1, 330 | "IO RX queue %" PRIu32 " stats: %" PRIu64 " pps\n", i, pps); 331 | } 332 | 333 | for (i = 0; i < lp->rx.n_rings; i++) { 334 | uint64_t pps; 335 | 336 | if (lp->rx.rings_pkts[0] == 0) { 337 | continue; 338 | } 339 | pps = lp->rx.rings_pkts[i] / 340 | (TSC2US(now - lp->stats_tsc) / US_PER_S); 341 | lp->rx.rings_pkts[i] = 0; 342 | 343 | RTE_LOG( 344 | DEBUG, 345 | USER1, 346 | "IO RX worker ring %" PRIu32 " stats: %" PRIu64 347 | " pps\n", i, pps); 348 | } 349 | } 350 | 351 | static void 352 | tx_stats(struct io_lc_cfg *lp, uint64_t now) 353 | { 354 | if (unlikely(lp->tx.n_nic_ports == 0)) { 355 | return; 356 | } 357 | if (now) { 358 | ; 359 | } 360 | } 361 | 362 | void 363 | io_lcore_main_loop(__attribute__((unused)) void *arg) 364 | { 365 | struct io_lc_cfg *lp; 366 | uint32_t n_wrks_rx, n_wrks_tx; 367 | uint32_t lcore, idle, i, stats; 368 | uint32_t rx_r_burst, rx_w_burst, tx_r_burst, tx_w_burst; 369 | 370 | lcore = rte_lcore_id(); 371 | lp = &cfg.lcores[lcore].io; 372 | n_wrks_rx = lp->rx.n_rings; 373 | n_wrks_tx = __builtin_popcount(lp->tx.workers_mask); 374 | 375 | rx_r_burst = cfg.io_rx_read_burst_size; 376 | rx_w_burst = cfg.io_rx_write_burst_size; 377 | tx_r_burst = cfg.io_tx_read_burst_size; 378 | tx_w_burst = cfg.io_tx_write_burst_size; 379 | 380 | tsc_per_us = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S; 381 | 382 | i = 0; 383 | idle = 0; 384 | stats = 0; 385 | for (;;) { 386 | if (LCORE_IO_FLUSH && unlikely(i == LCORE_IO_FLUSH)) { 387 | if (lp->pending) { 388 | /* Pending may be reset by the flush handler */ 389 | lp->pending = 0; 390 | if (likely(lp->rx.n_nic_queues > 0)) { 391 | flush_rx_buffers(lp, n_wrks_rx); 392 | } 393 | if (likely(lp->tx.n_nic_ports > 0)) { 394 | flush_tx_buffers(lp); 395 | } 396 | } 397 | i = 0; 398 | } 399 | if (APP_STATS && unlikely(stats == APP_STATS)) { 400 | uint64_t now = now_tsc; 401 | uint64_t elapsed_us = TSC2US(now - lp->stats_tsc); 402 | if (elapsed_us > US_PER_S) { 403 | rx_stats(lp, now); 404 | tx_stats(lp, now); 405 | lp->stats_tsc = now; 406 | } 407 | stats = 0; 408 | } 409 | if (lp->rx.n_nic_queues > 0) { 410 | if (rx_nic_pkts(lp, n_wrks_rx, rx_r_burst, rx_w_burst)) { 411 | idle = 0; 412 | } 413 | } 414 | if (lp->tx.n_nic_ports > 0) { 415 | if (tx_nic_pkts(lp, n_wrks_tx, tx_r_burst, tx_w_burst)) { 416 | idle = 0; 417 | } 418 | } 419 | idle_heuristic(idle); 420 | if (lp->pending == 0) { 421 | idle++; 422 | } else { 423 | idle = 0; 424 | } 425 | i++; 426 | stats++; 427 | } 428 | } 429 | -------------------------------------------------------------------------------- /dpdk/firewall/ip6.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef IP6_H_ 36 | #define IP6_H_ 37 | 38 | #include "packet.h" 39 | 40 | /* 41 | * IPv6 extension headers. 42 | * 43 | * The extension header are filtered only for presence using a bit 44 | * vector with a flag for each header. 45 | */ 46 | #define IP6_EH_FRAGMENT (1 << 0) 47 | #define IP6_EH_HOPOPTS (1 << 1) 48 | #define IP6_EH_ROUTING (1 << 2) 49 | #define IP6_EH_AH (1 << 3) 50 | #define IP6_EH_ESP (1 << 4) 51 | #define IP6_EH_DSTOPTS (1 << 5) 52 | #define IP6_EH_RTHDR0 (1 << 6) 53 | #define IP6_EH_RTHDR2 (1 << 7) 54 | #define IP6_EH_UNKNOWN (1 << 8) 55 | #define IP6_EH_INVALID (1 << 9) 56 | 57 | /* 58 | * This code is derived from FreeBSD: 59 | */ 60 | static inline uint32_t 61 | ip6_parse_hdrs(struct rte_mbuf *m, uint8_t **l4hdr, uint16_t *l4proto) 62 | { 63 | struct ipv6_hdr *iphdr; 64 | void *ulp; 65 | uint32_t exthdrs, hlen; 66 | uint8_t proto; 67 | 68 | /* 69 | * PULLUP_TO(len, p, T) sets p to point at the offset "len" in the mbuf. 70 | * WARNING: the pointer might become stale after other pullups 71 | * (but we never use it this way). 72 | */ 73 | #define PULLUP_TO(_len, p, T) PULLUP_LEN(_len, p, sizeof(T)) 74 | #define PULLUP_LEN(_len, p, T) \ 75 | do { \ 76 | uint16_t x = (_len) + T; \ 77 | if ((m)->data_len < x) { \ 78 | p = NULL; \ 79 | goto fail; \ 80 | } \ 81 | p = (rte_pktmbuf_mtod(m, uint8_t *)) + (_len); \ 82 | } while (0) 83 | 84 | *l4hdr = NULL; 85 | *l4proto = 0; 86 | exthdrs = 0; 87 | hlen = sizeof(struct ether_hdr) + sizeof(struct ipv6_hdr); 88 | ulp = NULL; 89 | iphdr = (struct ipv6_hdr *)(rte_pktmbuf_mtod(m, uint8_t *)+ 90 | sizeof(struct ether_hdr)); 91 | proto = iphdr->proto; 92 | 93 | while (ulp == NULL) { 94 | switch (proto) { 95 | case IPPROTO_ICMPV6: 96 | PULLUP_TO(hlen, ulp, struct icmp6_hdr); 97 | *l4hdr = ulp; 98 | *l4proto = proto; 99 | break; 100 | 101 | case IPPROTO_TCP: 102 | PULLUP_TO(hlen, ulp, struct tcphdr); 103 | *l4hdr = ulp; 104 | *l4proto = proto; 105 | break; 106 | 107 | case IPPROTO_SCTP: 108 | PULLUP_TO(hlen, ulp, struct sctphdr); 109 | *l4hdr = ulp; 110 | *l4proto = proto; 111 | break; 112 | 113 | case IPPROTO_UDP: 114 | PULLUP_TO(hlen, ulp, struct udphdr); 115 | *l4hdr = ulp; 116 | *l4proto = proto; 117 | break; 118 | 119 | case IPPROTO_HOPOPTS: /* RFC 2460 */ 120 | PULLUP_TO(hlen, ulp, struct ip6_hbh); 121 | exthdrs |= IP6_EH_HOPOPTS; 122 | hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3; 123 | proto = ((struct ip6_hbh *)ulp)->ip6h_nxt; 124 | ulp = NULL; 125 | break; 126 | 127 | case IPPROTO_ROUTING: /* RFC 2460 */ 128 | PULLUP_TO(hlen, ulp, struct ip6_rthdr); 129 | exthdrs |= IP6_EH_ROUTING; 130 | hlen += (((struct ip6_rthdr *)ulp)->ip6r_len + 1) << 3; 131 | proto = ((struct ip6_rthdr *)ulp)->ip6r_nxt; 132 | ulp = NULL; 133 | break; 134 | 135 | case IPPROTO_FRAGMENT: /* RFC 2460 */ 136 | PULLUP_TO(hlen, ulp, struct ip6_frag); 137 | exthdrs |= IP6_EH_FRAGMENT; 138 | hlen += sizeof(struct ip6_frag); 139 | proto = ((struct ip6_frag *)ulp)->ip6f_nxt; 140 | ulp = NULL; 141 | break; 142 | 143 | case IPPROTO_DSTOPTS: /* RFC 2460 */ 144 | PULLUP_TO(hlen, ulp, struct ip6_hbh); 145 | exthdrs |= IP6_EH_DSTOPTS; 146 | hlen += (((struct ip6_hbh *)ulp)->ip6h_len + 1) << 3; 147 | proto = ((struct ip6_hbh *)ulp)->ip6h_nxt; 148 | ulp = NULL; 149 | break; 150 | 151 | case IPPROTO_AH: /* RFC 2402 */ 152 | PULLUP_TO(hlen, ulp, struct ip6_ext); 153 | exthdrs |= IP6_EH_AH; 154 | hlen += (((struct ip6_ext *)ulp)->ip6e_len + 2) << 2; 155 | proto = ((struct ip6_ext *)ulp)->ip6e_nxt; 156 | ulp = NULL; 157 | break; 158 | 159 | case IPPROTO_ESP: /* RFC 2406 */ 160 | PULLUP_TO(hlen, ulp, uint32_t); /* SPI, Seq# */ 161 | /* 162 | * Anything past Seq# is variable length and data 163 | * past this ext. header is encrypted. 164 | */ 165 | exthdrs |= IP6_EH_ESP; 166 | break; 167 | 168 | case IPPROTO_NONE: /* RFC 2460 */ 169 | /* 170 | * Packet ends here, and IPv6 header has already been 171 | * pulled up. If ip6e_len != 0 then octets must be 172 | * ignored. 173 | */ 174 | goto done; 175 | 176 | case IPPROTO_OSPFIGP: 177 | /* XXX OSPF header check? */ 178 | PULLUP_TO(hlen, ulp, struct ip6_ext); 179 | break; 180 | 181 | case IPPROTO_PIM: 182 | /* XXX PIM header check? */ 183 | PULLUP_TO(hlen, ulp, struct pim); 184 | break; 185 | 186 | case IPPROTO_IPV6: /* RFC 2893 */ 187 | PULLUP_TO(hlen, ulp, struct ipv6_hdr); 188 | break; 189 | 190 | case IPPROTO_IPV4: /* RFC 2893 */ 191 | PULLUP_TO(hlen, ulp, struct ipv4_hdr); 192 | break; 193 | 194 | default: 195 | RTE_LOG(WARNING, ACL, "parse_ip6_hdrs: unknown header " 196 | "type: %x\n", proto); 197 | exthdrs |= IP6_EH_UNKNOWN; 198 | PULLUP_TO(hlen, ulp, struct ip6_ext); 199 | break; 200 | } 201 | } 202 | 203 | #undef PULLUP_TO 204 | #undef PULLUP_LEN 205 | 206 | done: 207 | return exthdrs; 208 | 209 | fail: 210 | *l4hdr = NULL; 211 | exthdrs = IP6_EH_INVALID; 212 | 213 | return exthdrs; 214 | } 215 | 216 | #endif /* IP6_H_ */ 217 | -------------------------------------------------------------------------------- /dpdk/firewall/kni.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #include 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "main.h" 46 | #include "util.h" 47 | #include "runtime.h" 48 | #include "packet.h" 49 | #include "forward.h" 50 | 51 | /* Total octets in ethernet header */ 52 | #define KNI_ETHER_HEADER_SIZE 14 53 | 54 | /* Total octets in the FCS */ 55 | #define KNI_ETHER_FCS_SIZE 4 56 | 57 | struct rte_kni * 58 | kni_alloc_port(uint8_t port, struct lc_cfg *lcp) 59 | { 60 | struct ifreq ifr; 61 | struct rte_kni_conf conf; 62 | struct rte_kni *kni; 63 | struct nic_cfg *nic; 64 | int ret, sock; 65 | 66 | kni = NULL; 67 | sock = -1; 68 | ret = -1; 69 | nic = &cfg.ifaces[port]; 70 | memset(&conf, 0, sizeof(conf)); 71 | snprintf(conf.name, sizeof(conf.name), "mitra%u", port); 72 | conf.group_id = port; 73 | conf.mbuf_size = MBUF_SIZE; 74 | 75 | if (lcp->worker.kni.is_master) { 76 | struct rte_kni_ops ops; 77 | struct rte_eth_dev_info dev_info; 78 | 79 | memset(&dev_info, 0, sizeof(dev_info)); 80 | rte_eth_dev_info_get(port, &dev_info); 81 | conf.addr = dev_info.pci_dev->addr; 82 | conf.id = dev_info.pci_dev->id; 83 | 84 | memset(&ops, 0, sizeof(ops)); 85 | ops.port_id = port; 86 | ops.change_mtu = kni_change_mtu; 87 | ops.config_network_if = kni_config_network_if; 88 | 89 | kni = rte_kni_alloc(lcp->pool, &conf, &ops); 90 | } else { 91 | kni = rte_kni_alloc(lcp->pool, &conf, NULL); 92 | } 93 | 94 | if (kni == NULL) { 95 | RTE_LOG(ERR, USER1, "Could not allocate KNI for port %u!", 96 | port); 97 | goto done; 98 | } 99 | /* Configure KNI interface */ 100 | if ((ret = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { 101 | goto done; 102 | } 103 | sock = ret; 104 | 105 | /* Set the mac address */ 106 | strlcpy(ifr.ifr_name, conf.name, IFNAMSIZ); 107 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 108 | ether_addr_copy( 109 | &nic->hwaddr, (struct ether_addr *)&ifr.ifr_hwaddr.sa_data); 110 | if ((ret = ioctl(sock, SIOCSIFHWADDR, &ifr) < 0)) { 111 | goto done; 112 | } 113 | /* Bring the interface up */ 114 | /* 115 | * if ((ret = ioctl(sock, SIOCGIFFLAGS, &ifr)) < 0) { goto done; } 116 | * 117 | * ifr.ifr_flags |= IFF_UP; if ((ret = ioctl(sock, SIOCSIFFLAGS, &ifr)) 118 | * < 0) { goto done; } 119 | */ 120 | done: 121 | if (sock >= 0) { 122 | close(sock); 123 | } 124 | if (ret < 0 && kni) { 125 | rte_kni_release(kni); 126 | kni = NULL; 127 | } 128 | return kni; 129 | } 130 | 131 | int 132 | kni_change_mtu(uint8_t port_id, unsigned int new_mtu) 133 | { 134 | int ret; 135 | struct rte_eth_conf conf; 136 | 137 | return 0; 138 | 139 | if (port_id >= rte_eth_dev_count()) { 140 | RTE_LOG(DEBUG, KNI, "Invalid port id %d\n", port_id); 141 | return -EINVAL; 142 | } 143 | RTE_LOG(DEBUG, KNI, "Change MTU of port %d to %u\n", port_id, new_mtu); 144 | 145 | /* Stop specific port */ 146 | rte_eth_dev_stop(port_id); 147 | 148 | rte_memcpy(&conf, &port_conf, sizeof(conf)); 149 | /* Set new MTU */ 150 | if (new_mtu > ETHER_MAX_LEN) 151 | conf.rxmode.jumbo_frame = 1; 152 | else 153 | conf.rxmode.jumbo_frame = 0; 154 | 155 | /* MTU + length of header + length of FCS = max pkt length */ 156 | conf.rxmode.max_rx_pkt_len = 157 | new_mtu + KNI_ETHER_HEADER_SIZE + KNI_ETHER_FCS_SIZE; 158 | ret = rte_eth_dev_configure(port_id, 1, 1, &conf); 159 | if (ret < 0) { 160 | RTE_LOG(DEBUG, KNI, "Fail to reconfigure port %d\n", port_id); 161 | return ret; 162 | } 163 | /* Restart specific port */ 164 | ret = rte_eth_dev_start(port_id); 165 | if (ret < 0) { 166 | RTE_LOG(DEBUG, KNI, "Fail to restart port %d\n", port_id); 167 | return ret; 168 | } 169 | return 0; 170 | } 171 | 172 | int 173 | kni_config_network_if(uint8_t port_id, uint8_t if_up) 174 | { 175 | int ret = 0; 176 | 177 | return 0; 178 | 179 | if (port_id >= rte_eth_dev_count() || port_id >= RTE_MAX_ETHPORTS) { 180 | RTE_LOG(DEBUG, KNI, "Invalid port id %d\n", port_id); 181 | return -EINVAL; 182 | } 183 | RTE_LOG(DEBUG, KNI, "Configure network interface of %d %s\n", 184 | port_id, if_up ? "up" : "down"); 185 | 186 | if (if_up != 0) { /* Configure network interface up */ 187 | rte_eth_dev_stop(port_id); 188 | ret = rte_eth_dev_start(port_id); 189 | } else { /* Configure network interface down */ 190 | rte_eth_dev_stop(port_id); 191 | } 192 | if (ret < 0) { 193 | RTE_LOG(DEBUG, KNI, "Failed to start port %d\n", port_id); 194 | } 195 | return ret; 196 | } 197 | 198 | uint32_t 199 | kni_fwd_pkts_to_kernel(struct worker_lc_cfg *lp, uint32_t burst) 200 | { 201 | uint32_t n_rings, r, n_pkts; 202 | 203 | n_pkts = 0; 204 | n_rings = lp->n_irings; 205 | 206 | for (r = 0; r < n_rings; r++) { 207 | struct rte_ring *iring = lp->irings[r]; 208 | struct rte_mbuf **ibuf = lp->ibuf.array; 209 | uint32_t base, cur, n_rx, n_tx, port; 210 | 211 | n_rx = rte_ring_sc_dequeue_burst(iring, (void **)ibuf, burst); 212 | if (unlikely(n_rx > burst)) { 213 | RTE_LOG(CRIT, USER1, "KNI: error receiving on ring!\n"); 214 | return n_pkts; 215 | } 216 | if (unlikely(n_rx == 0)) { 217 | continue; 218 | } 219 | n_pkts += n_rx; 220 | base = 0; 221 | cur = 0; 222 | port = ibuf[0]->port; 223 | while (base < n_rx) { 224 | struct rte_kni *kni; 225 | size_t len; 226 | int ret; 227 | 228 | port = ibuf[cur]->port; 229 | while (cur < n_rx && ibuf[cur]->port == port) { 230 | if (arp_chk_gw_pkt(ibuf[cur], now_tsc)) { 231 | cfg.gws_ts = now_tsc; 232 | } 233 | /* 234 | * The pkt_tag_vlan may change the packet by 235 | * adding a vlan header 236 | */ 237 | pkt_add_vlan_hdr(ibuf[cur]); 238 | 239 | cur++; 240 | } 241 | 242 | /* Burst packets to KNI */ 243 | len = cur - base; 244 | 245 | kni = lp->kni.kni[lp->kni.port_to_kni[port]]; 246 | n_tx = rte_kni_tx_burst(kni, ibuf + base, len); 247 | ret = rte_kni_handle_request(kni); 248 | if (ret < 0) { 249 | RTE_LOG(CRIT, USER1, 250 | "Error sending packets to kernel.\n"); 251 | } 252 | if (unlikely(n_tx < len)) { 253 | util_free_mbufs_burst( 254 | &ibuf[base + n_tx], len - n_tx); 255 | } 256 | base = cur; 257 | } 258 | } 259 | 260 | return n_pkts; 261 | } 262 | 263 | uint32_t 264 | kni_fwd_pkts_to_nic(struct worker_lc_cfg *lp, uint32_t burst) 265 | { 266 | uint32_t r, port, n_kni, n_pkts; 267 | 268 | n_pkts = 0; 269 | n_kni = lp->kni.n_kni; 270 | 271 | for (r = 0; r < n_kni; r++) { 272 | struct rte_kni *kni; 273 | struct rte_mbuf **outbuf; 274 | unsigned i, n_rx, n_tx; 275 | 276 | kni = lp->kni.kni[r]; 277 | port = lp->kni.kni_to_port[r]; 278 | outbuf = lp->obuf[port].array; 279 | 280 | n_rx = rte_kni_rx_burst(kni, outbuf, burst); 281 | if (unlikely(n_rx > burst)) { 282 | RTE_LOG(CRIT, USER1, "KNI: error receiving on ring!\n"); 283 | return n_pkts; 284 | } 285 | if (unlikely(n_rx == 0)) { 286 | continue; 287 | } 288 | for (i = 0; i < n_rx; i++) { 289 | outbuf[i]->port = port; 290 | outbuf[i]->udata64 |= 291 | PKT_META_ROUTED | PKT_META_VLAN_TAG; 292 | } 293 | 294 | /* Burst packets to IO tx lcore */ 295 | n_tx = rte_ring_sp_enqueue_burst( 296 | lp->orings[port], (void **)outbuf, n_rx); 297 | 298 | if (unlikely(n_tx < n_rx)) { 299 | util_free_mbufs_burst(&outbuf[n_tx], n_rx - n_tx); 300 | } 301 | n_pkts += n_rx; 302 | } 303 | 304 | return n_pkts; 305 | } 306 | -------------------------------------------------------------------------------- /dpdk/firewall/main.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "main.h" 47 | 48 | void usage(const char *); 49 | 50 | void 51 | usage(const char *name) 52 | { 53 | fprintf(stderr, "usage: %s: \n", name); 54 | } 55 | 56 | static void 57 | hup_signal_handler(int signum __attribute__((unused))) 58 | { 59 | if (reload_fw != 0) { 60 | return; 61 | } 62 | reload_fw = 1; 63 | } 64 | 65 | static void 66 | usr1_signal_handler(int signum __attribute__((unused))) 67 | { 68 | if (dump_fw_counters != 0) { 69 | return; 70 | } 71 | dump_fw_counters = 1; 72 | } 73 | 74 | static int 75 | install_signal_handlers(void) 76 | { 77 | struct sigaction sa; 78 | sigset_t set; 79 | 80 | memset(&sa, 0, sizeof(sa)); 81 | sa.sa_handler = hup_signal_handler; 82 | sa.sa_flags = SA_RESTART; 83 | sigfillset(&sa.sa_mask); 84 | if (sigaction(SIGHUP, &sa, NULL) != 0) { 85 | RTE_LOG(CRIT, USER1, "Error registering SIGHUP handler\n"); 86 | return -1; 87 | } 88 | sa.sa_handler = usr1_signal_handler; 89 | if (sigaction(SIGUSR1, &sa, NULL) != 0) { 90 | RTE_LOG(CRIT, USER1, "Error registering SIGUSR1 handler\n"); 91 | return -1; 92 | } 93 | /* block (ignore) sigpipes for this and all the child threads */ 94 | sigemptyset(&set); 95 | sigaddset(&set, SIGPIPE); 96 | if (pthread_sigmask(SIG_BLOCK, &set, NULL) != 0) { 97 | RTE_LOG(CRIT, USER1, "Error setting signal mask\n"); 98 | return -1; 99 | } 100 | return 0; 101 | } 102 | 103 | int 104 | main(int argc, char *argv[]) 105 | { 106 | uint32_t lcore; 107 | int ret; 108 | 109 | /* Init EAL */ 110 | ret = rte_eal_init(argc, argv); 111 | if (ret < 0) 112 | return -1; 113 | argc -= ret; 114 | argv += ret; 115 | 116 | /* Parse configuration file */ 117 | if (argc < 2) { 118 | usage(argv[0]); 119 | return -1; 120 | } 121 | ret = cfg_parse_file(argv[1]); 122 | if (ret < 0) { 123 | fprintf(stderr, "Could not parse configuration file [%s]\n", 124 | argv[1]); 125 | return ret; 126 | } 127 | if ((ret = install_signal_handlers()) != 0) { 128 | return ret; 129 | } 130 | /* Initialize the application */ 131 | init_app(); 132 | cfg_print_settings(); 133 | 134 | /* Launch per-lcore init on every lcore */ 135 | rte_eal_mp_remote_launch(lcore_main_loop, NULL, CALL_MASTER); 136 | RTE_LCORE_FOREACH_SLAVE(lcore) { 137 | if (rte_eal_wait_lcore(lcore) < 0) { 138 | return -1; 139 | } 140 | } 141 | 142 | return 0; 143 | } 144 | -------------------------------------------------------------------------------- /dpdk/firewall/main.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef _MAIN_H_ 36 | #define _MAIN_H_ 37 | 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | /* Processor sockets */ 47 | #ifndef MAX_SOCKETS 48 | #define MAX_SOCKETS 2 49 | #endif 50 | 51 | /* Logical cores */ 52 | #ifndef MAX_LCORES 53 | #define MAX_LCORES RTE_MAX_LCORE 54 | #endif 55 | 56 | /* Network interfaces (ports) */ 57 | #ifndef MAX_NIC_PORTS 58 | #define MAX_NIC_PORTS RTE_MAX_ETHPORTS 59 | #endif 60 | 61 | #ifndef MAX_VLANS 62 | #define MAX_VLANS 4096 63 | #endif 64 | 65 | /* Must be a power of 2 */ 66 | #ifndef MAX_GWS 67 | #define MAX_GWS 8 68 | #endif 69 | 70 | #ifndef MAX_RX_QUEUES_PER_NIC_PORT 71 | #define MAX_RX_QUEUES_PER_NIC_PORT 16 72 | #endif 73 | 74 | #ifndef MAX_TX_QUEUES_PER_NIC_PORT 75 | #define MAX_TX_QUEUES_PER_NIC_PORT 16 76 | #endif 77 | 78 | #ifndef MAX_IO_LCORES 79 | #define MAX_IO_LCORES 16 80 | #endif 81 | #if (MAX_IO_LCORES > MAX_LCORES) 82 | #error "MAX_IO_LCORES is too big" 83 | #endif 84 | 85 | #ifndef MAX_NIC_RX_QUEUES_PER_IO_LCORE 86 | #define MAX_NIC_RX_QUEUES_PER_IO_LCORE 16 87 | #endif 88 | 89 | #ifndef MAX_NIC_TX_PORTS_PER_IO_LCORE 90 | #define MAX_NIC_TX_PORTS_PER_IO_LCORE 6 91 | #endif 92 | #if (MAX_NIC_TX_PORTS_PER_IO_LCORE > MAX_NIC_PORTS) 93 | #error "MAX_NIC_TX_PORTS_PER_IO_LCORE too big" 94 | #endif 95 | 96 | 97 | #ifndef MAX_NIC_LEN 98 | #define MAX_NIC_LEN 16 99 | #endif 100 | 101 | #ifndef MAX_WORKER_LCORES 102 | #define MAX_WORKER_LCORES 16 103 | #endif 104 | #if (MAX_WORKER_LCORES > MAX_LCORES) 105 | #error "MAX_WORKER_LCORES is too big" 106 | #endif 107 | 108 | #ifndef MAX_CTRL_LCORES 109 | #define MAX_CTRL_LCORES 2 110 | #endif 111 | 112 | #ifndef MAX_FW_LCORES 113 | #define MAX_FW_LCORES 4 114 | #endif 115 | 116 | #ifndef MAX_OL_LCORES 117 | #define MAX_OL_LCORES 2 118 | #endif 119 | 120 | #ifndef MAX_OL_LCORES 121 | #define MAX_OL_LCORES 2 122 | #endif 123 | 124 | /* Mempools */ 125 | #define BUF_SIZE 2048 126 | #ifndef MBUF_SIZE 127 | #define MBUF_SIZE (BUF_SIZE + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) 128 | #endif 129 | 130 | /* 131 | * TODO: set sensible sizes here 132 | */ 133 | #ifndef MEMPOOL_BUFFERS 134 | #define MEMPOOL_BUFFERS 8192 * 4 135 | #endif 136 | 137 | #ifndef MEMPOOL_CACHE_SIZE 138 | #define MEMPOOL_CACHE_SIZE 256 139 | #endif 140 | 141 | /* NIC RX */ 142 | #ifndef NIC_RX_RING_SIZE 143 | #define NIC_RX_RING_SIZE 256 144 | #endif 145 | 146 | /* NIC TX */ 147 | #ifndef NIC_TX_RING_SIZE 148 | #define NIC_TX_RING_SIZE 512 149 | #endif 150 | 151 | /* Software Rings */ 152 | #ifndef RING_RX_SIZE 153 | #define RING_RX_SIZE 512 154 | #endif 155 | 156 | #ifndef RING_TX_SIZE 157 | #define RING_TX_SIZE 512 158 | #endif 159 | 160 | /* Bursts */ 161 | #ifndef MBUF_ARRAY_SIZE 162 | #define MBUF_ARRAY_SIZE 512 163 | #endif 164 | 165 | #ifndef BURST_SIZE_IO_RX_READ 166 | #define BURST_SIZE_IO_RX_READ 32 167 | #endif 168 | #if (BURST_SIZE_IO_RX_READ > MBUF_ARRAY_SIZE) 169 | #error "BURST_SIZE_IO_RX_READ is too big" 170 | #endif 171 | 172 | #ifndef BURST_SIZE_IO_RX_WRITE 173 | #define BURST_SIZE_IO_RX_WRITE 32 174 | #endif 175 | #if (BURST_SIZE_IO_RX_WRITE > MBUF_ARRAY_SIZE) 176 | #error "BURST_SIZE_IO_RX_WRITE is too big" 177 | #endif 178 | 179 | #ifndef BURST_SIZE_IO_TX_READ 180 | #define BURST_SIZE_IO_TX_READ 32 181 | #endif 182 | #if (BURST_SIZE_IO_TX_READ > MBUF_ARRAY_SIZE) 183 | #error "BURST_SIZE_IO_TX_READ is too big" 184 | #endif 185 | 186 | #ifndef BURST_SIZE_IO_TX_WRITE 187 | #define BURST_SIZE_IO_TX_WRITE 32 188 | #endif 189 | #if (BURST_SIZE_IO_TX_WRITE > MBUF_ARRAY_SIZE) 190 | #error "BURST_SIZE_IO_TX_WRITE is too big" 191 | #endif 192 | 193 | #ifndef BURST_SIZE_WORKER_READ 194 | #define BURST_SIZE_WORKER_READ 32 195 | #endif 196 | #if ((2 * BURST_SIZE_WORKER_READ) > MBUF_ARRAY_SIZE) 197 | #error "BURST_SIZE_WORKER_READ is too big" 198 | #endif 199 | 200 | #ifndef BURST_SIZE_WORKER_WRITE 201 | #define BURST_SIZE_WORKER_WRITE 32 202 | #endif 203 | #if (BURST_SIZE_WORKER_WRITE > MBUF_ARRAY_SIZE) 204 | #error "BURST_SIZE_WORKER_WRITE is too big" 205 | #endif 206 | 207 | #ifndef BATCH_SIZE_ACL 208 | #define BATCH_SIZE_ACL BURST_SIZE_WORKER_READ 209 | #endif 210 | #if ((2 * BATCH_SIZE_ACL) > MBUF_ARRAY_SIZE) 211 | #error "BATCH_SIZE_ACL is too big" 212 | #endif 213 | 214 | #if (BATCH_SIZE_ACL % 2 != 0) 215 | #error "BATCH_SIZE_ACL must be a power of two" 216 | #endif 217 | 218 | #define MAX_ZONE_LEN 32 219 | #define MAX_ZONES 2 220 | #define MAX_NAT_ENTRIES 1024 221 | #define MAX_ACL_COUNTERS 16 222 | #define MAX_FILE_PATH 256 223 | #define CONF_PATH "etc" 224 | #define ZONE_PATH CONF_PATH"/zones" 225 | #define RULE_PATH ZONE_PATH"/rules" 226 | 227 | 228 | #define OL_MEMPOOL_SIZE 8192 229 | #define MAX_FRAG_NUM RTE_LIBRTE_IP_FRAG_MAX_FRAG 230 | #define FRAG_TABLE_BUCKETS 16 231 | 232 | #define NIC_FLAG_REVERSE 1 << 0 233 | #define NIC_FLAG_BOND_IFACE 1 << 1 234 | #define NIC_FLAG_BOND_SLAVE 1 << 2 235 | #define NIC_FLAG_TX_ON 1 << 3 236 | 237 | struct mbuf_array { 238 | struct rte_mbuf *array[MBUF_ARRAY_SIZE]; 239 | uint32_t n_mbufs; 240 | }; 241 | 242 | enum lc_type { 243 | LCORE_TYPE_NONE = 0, 244 | LCORE_TYPE_IO, 245 | LCORE_TYPE_WORKER, 246 | }; 247 | 248 | enum worker_type { 249 | WORKER_TYPE_FW = 0, 250 | WORKER_TYPE_NAT, 251 | WORKER_TYPE_CTRL_KNI, 252 | WORKER_TYPE_CTRL_TAP 253 | }; 254 | 255 | enum worker_ol_type { 256 | WORKER_OL_OFF = 0, 257 | WORKER_OL_CLNT, 258 | WORKER_OL_PROV, 259 | WORKER_OL_NUM 260 | }; 261 | 262 | struct nic_cfg { 263 | char zone[MAX_ZONE_LEN]; 264 | struct ether_addr hwaddr; 265 | uint8_t slaves[MAX_NIC_PORTS]; 266 | uint8_t n_slaves; 267 | uint8_t rx_queues[MAX_RX_QUEUES_PER_NIC_PORT]; 268 | 269 | uint8_t flags; 270 | 271 | volatile uint8_t lacp; 272 | }; 273 | 274 | struct io_lc_cfg { 275 | /* I/O RX */ 276 | struct { 277 | /* NIC */ 278 | struct { 279 | uint8_t port; 280 | uint8_t queue; 281 | } nic_queues[MAX_RX_QUEUES_PER_NIC_PORT]; 282 | uint32_t n_nic_queues; 283 | 284 | /* Rings */ 285 | struct rte_ring *rings[MAX_WORKER_LCORES]; 286 | uint32_t n_rings; 287 | 288 | /* Internal buffers */ 289 | struct mbuf_array ibuf; 290 | struct mbuf_array obuf[MAX_WORKER_LCORES]; 291 | uint8_t obuf_flush[MAX_WORKER_LCORES]; 292 | 293 | /* Connected workers */ 294 | uint32_t workers_mask; 295 | 296 | /* Stats */ 297 | uint64_t nic_q_pkts[MAX_NIC_RX_QUEUES_PER_IO_LCORE]; 298 | uint64_t rings_pkts[MAX_WORKER_LCORES]; 299 | } rx; 300 | 301 | /* I/O TX */ 302 | struct { 303 | /* Rings */ 304 | struct rte_ring *rings[MAX_NIC_PORTS][MAX_WORKER_LCORES]; 305 | 306 | /* NIC */ 307 | uint8_t nic_ports[MAX_NIC_TX_PORTS_PER_IO_LCORE]; 308 | uint32_t n_nic_ports; 309 | uint32_t workers_mask; 310 | 311 | /* Internal buffers */ 312 | struct mbuf_array obuf[MAX_NIC_TX_PORTS_PER_IO_LCORE]; 313 | uint8_t obuf_flush[MAX_NIC_TX_PORTS_PER_IO_LCORE]; 314 | 315 | /* Stats */ 316 | uint64_t rings_pkts[MAX_WORKER_LCORES]; 317 | uint64_t nic_pkts[MAX_NIC_TX_PORTS_PER_IO_LCORE]; 318 | } tx; 319 | 320 | uint64_t stats_tsc; 321 | uint8_t pending; 322 | }; 323 | 324 | struct wrk_ring { 325 | struct rte_ring *ring; 326 | struct mbuf_array obuf; 327 | uint8_t obuf_flush; 328 | }; 329 | 330 | struct fw_ctx; 331 | 332 | struct fw_lc_cfg { 333 | struct fw_ctx *ctx; 334 | }; 335 | 336 | struct kni_lc_cfg { 337 | struct rte_kni *kni[MAX_NIC_PORTS]; 338 | int8_t port_to_kni[MAX_NIC_PORTS]; 339 | int8_t kni_to_port[MAX_NIC_PORTS]; 340 | uint32_t n_kni; 341 | uint8_t is_master; 342 | }; 343 | 344 | struct tap_lc_cfg { 345 | int taps[MAX_NIC_PORTS]; 346 | int port_to_tap[MAX_NIC_PORTS]; 347 | int8_t tap_to_port[MAX_NIC_PORTS]; 348 | uint32_t n_taps; 349 | }; 350 | 351 | struct rt_ctx { 352 | struct ether_addr ogws[MAX_GWS]; 353 | struct ether_addr igws[MAX_GWS]; 354 | uint64_t gws_ts; 355 | uint8_t n_igws; 356 | uint8_t n_ogws; 357 | uint8_t ovlan; 358 | uint8_t reassembly; 359 | }; 360 | 361 | struct worker_lc_cfg { 362 | union { 363 | struct fw_lc_cfg fw; 364 | struct kni_lc_cfg kni; 365 | struct tap_lc_cfg tap; 366 | }; 367 | 368 | /* Rings */ 369 | struct rte_ring *irings[MAX_LCORES]; 370 | uint16_t n_irings; 371 | struct rte_ring *orings[MAX_NIC_PORTS]; 372 | 373 | /* Internal buffers */ 374 | struct mbuf_array ibuf; 375 | struct mbuf_array obuf[MAX_NIC_PORTS]; 376 | uint8_t obuf_flush[MAX_NIC_PORTS]; 377 | 378 | /* Stats */ 379 | uint64_t irings_pkts[MAX_LCORES]; 380 | uint64_t orings_pkts[MAX_NIC_PORTS]; 381 | uint64_t crings_pkts[MAX_CTRL_LCORES]; 382 | 383 | /* Control path lcores */ 384 | struct wrk_ring crings[MAX_CTRL_LCORES]; 385 | uint32_t n_crings; 386 | 387 | /* Routing */ 388 | struct rt_ctx rt; 389 | 390 | /* Offloaders (fragment reassembly, syn flood handlers, etc.) */ 391 | struct wrk_ring ol_rings[MAX_OL_LCORES]; 392 | uint32_t n_ol_rings; 393 | 394 | enum worker_type type; 395 | enum worker_ol_type ol; 396 | uint8_t pending; 397 | uint8_t ctrlplane; 398 | uint8_t id; 399 | }; 400 | 401 | struct lc_cfg { 402 | union { 403 | struct io_lc_cfg io; 404 | struct worker_lc_cfg worker; 405 | }; 406 | enum lc_type type; 407 | struct rte_mempool *pool; 408 | } __rte_cache_aligned; 409 | 410 | union in6_xmm_addr { 411 | struct in6_addr addr; 412 | __m128i xmm; 413 | }; 414 | 415 | struct vlan_info { 416 | struct in_addr ip; 417 | struct in_addr ip_net; 418 | struct in_addr ip_mask; 419 | union in6_xmm_addr ip6; 420 | union in6_xmm_addr ip6_net; 421 | union in6_xmm_addr ip6_mask; 422 | }; 423 | 424 | struct gw_addr { 425 | struct in_addr ip; 426 | struct ether_addr mac; 427 | uint16_t vlan; 428 | uint64_t update_ts; 429 | uint64_t probe_ts; 430 | uint64_t probes; 431 | }; 432 | 433 | struct app_cfg { 434 | /* lcore */ 435 | struct lc_cfg lcores[MAX_LCORES]; 436 | 437 | /* Network interfaces */ 438 | struct nic_cfg ifaces[MAX_NIC_PORTS]; 439 | 440 | /* Network gateways */ 441 | struct gw_addr igws[MAX_GWS]; 442 | struct gw_addr ogws[MAX_GWS]; 443 | volatile uint16_t ivlan; 444 | volatile uint16_t ovlan; 445 | volatile uint8_t n_igws; 446 | volatile uint8_t n_ogws; 447 | volatile uint64_t gws_ts; 448 | 449 | /* Local IP addresses */ 450 | struct vlan_info vlans[MAX_VLANS]; 451 | volatile uint64_t vlans_ts; 452 | 453 | /* Main mbuf pools */ 454 | struct rte_mempool *pools[MAX_SOCKETS]; 455 | 456 | /* Offload memory pools */ 457 | struct rte_mempool *ol_pools[MAX_SOCKETS]; 458 | 459 | /* Rings */ 460 | uint16_t nic_rx_ring_size; 461 | uint16_t nic_tx_ring_size; 462 | uint16_t ring_rx_size; 463 | uint16_t ring_tx_size; 464 | 465 | /* Burst sizes */ 466 | uint16_t io_rx_read_burst_size; 467 | uint16_t io_rx_write_burst_size; 468 | uint16_t io_tx_read_burst_size; 469 | uint16_t io_tx_write_burst_size; 470 | uint16_t worker_read_burst_size; 471 | uint16_t worker_write_burst_size; 472 | 473 | /* KNI ports */ 474 | uint16_t n_kni_ports; 475 | 476 | /* Fragmentation options */ 477 | uint16_t frag_max_flow_num; 478 | uint16_t frag_max_flow_ttl; 479 | 480 | } __rte_cache_aligned; 481 | 482 | extern struct app_cfg cfg; 483 | extern struct rte_eth_conf port_conf; 484 | extern volatile uint8_t reload_fw; 485 | extern volatile uint8_t dump_fw_counters; 486 | 487 | void cfg_print_settings(void); 488 | int cfg_parse_file(const char *); 489 | int cfg_lcore_for_nic_rx(uint32_t, uint32_t, uint32_t *); 490 | int cfg_lcore_for_nic_tx(uint32_t, uint32_t *); 491 | int cfg_is_socket_used(uint32_t); 492 | uint16_t cfg_nic_rx_queues_per_port(uint32_t); 493 | uint32_t cfg_lcores_io_rx(void); 494 | uint32_t cfg_lcores_worker(void); 495 | 496 | void init_app(void); 497 | int lcore_main_loop(void *); 498 | 499 | int kni_change_mtu(uint8_t, unsigned int); 500 | int kni_config_network_if(uint8_t, uint8_t); 501 | struct rte_kni *kni_alloc_port(uint8_t, struct lc_cfg *); 502 | 503 | int tap_create(const char *, struct nic_cfg *); 504 | int fw_init(void); 505 | void fw_reload(void); 506 | void fw_dump_counters(void); 507 | #endif /* _MAIN_H_ */ 508 | -------------------------------------------------------------------------------- /dpdk/firewall/nat.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #include "main.h" 34 | #include "packet.h" 35 | #include "acl.h" 36 | #include "nat.h" 37 | 38 | #define MAX_LINE 1024 39 | #define COMMENT_CHAR '#' 40 | 41 | void 42 | nat_free_rules(struct zone_cfg *zone) 43 | { 44 | uint32_t i; 45 | 46 | for (i = 0; i < RTE_DIM(zone->ip_nat_k); i++) { 47 | rte_hash_free(zone->ip_nat_k[i]); 48 | rte_free(zone->ip_nat_v[i]); 49 | } 50 | } 51 | 52 | static int 53 | init_ip_nat(struct zone_cfg *zone) 54 | { 55 | uint32_t i; 56 | int ret; 57 | 58 | struct rte_hash_parameters ip_nat_params = { 59 | .name = NULL, 60 | .entries = MAX_NAT_ENTRIES, 61 | .key_len = sizeof(struct in_addr), 62 | .hash_func = ip_hash_crc, 63 | .hash_func_init_val = 0, 64 | }; 65 | 66 | ret = -1; 67 | for (i = 0; i < RTE_DIM(zone->ip_nat_k); i++) { 68 | char name[64]; 69 | 70 | snprintf(name, sizeof(name), "ip_nat_%s_%u_%u", zone->name, 71 | zone->version, i); 72 | 73 | RTE_LOG(DEBUG, USER1, "Building hash table: %s\n", name); 74 | 75 | /* 76 | * XXX: ensure that both rte_hash_create and 77 | * rte_zmalloc_socket create a copy of the "name" string. 78 | */ 79 | ip_nat_params.name = name; 80 | ip_nat_params.socket_id = i; 81 | zone->ip_nat_k[i] = rte_hash_create(&ip_nat_params); 82 | if (zone->ip_nat_k[i] == NULL) { 83 | goto fail; 84 | } 85 | if ((zone->ip_nat_v[i] = rte_zmalloc_socket(name, 86 | MAX_NAT_ENTRIES * sizeof(uint32_t), 0, i)) == NULL) { 87 | goto fail; 88 | } 89 | } 90 | 91 | return 0; 92 | 93 | fail: 94 | nat_free_rules(zone); 95 | 96 | return ret; 97 | 98 | } 99 | 100 | static int 101 | parse_ip_nat_rule(char *str, struct zone_cfg *zone) 102 | { 103 | static const char *dlm = " \t\n"; 104 | char *s, *sp, *sn; 105 | uint32_t key, value, i; 106 | int32_t r; 107 | 108 | /* XXX: check inet_pton output */ 109 | s = strtok_r(str, dlm, &sp); 110 | 111 | /* Strip out netmask, if provided */ 112 | if ((sn = strstr(s, "/")) != NULL) { 113 | *sn = '\0'; 114 | } 115 | inet_pton(AF_INET, s, &key); 116 | 117 | s = strtok_r(NULL, dlm, &sp); 118 | if ((sn = strstr(s, "/")) != NULL) { 119 | *sn = '\0'; 120 | } 121 | inet_pton(AF_INET, s, &value); 122 | 123 | for (i = 0; i < RTE_DIM(zone->ip_nat_k); i++) { 124 | struct rte_hash *ht = zone->ip_nat_k[i]; 125 | r = rte_hash_add_key(ht, (void *)&key); 126 | if (r < 0) { 127 | return -1; 128 | } 129 | zone->ip_nat_v[i][r] = value; 130 | } 131 | 132 | return 0; 133 | } 134 | 135 | static int 136 | line_ignored(const char *buff) 137 | { 138 | int i = 0; 139 | 140 | /* Comment line */ 141 | if (buff[0] == COMMENT_CHAR) { 142 | return 1; 143 | } 144 | /* Empty line */ 145 | while (buff[i] != '\0') { 146 | if (!isspace(buff[i])) { 147 | return 0; 148 | } 149 | i++; 150 | } 151 | 152 | return 1; 153 | } 154 | 155 | static int 156 | parse_ip_nat(char *path, struct zone_cfg *zone, 157 | int (*parser) (char *, struct zone_cfg *)) 158 | { 159 | char buff[MAX_LINE]; 160 | FILE *fp; 161 | unsigned int i, ret; 162 | 163 | if ((fp = fopen(path, "rb")) == NULL) { 164 | return -1; 165 | } 166 | ret = -1; 167 | i = 0; 168 | while (fgets(buff, MAX_LINE, fp) != NULL) { 169 | i++; 170 | if (line_ignored(buff)) { 171 | continue; 172 | } 173 | if (parser(buff, zone) < 0) { 174 | goto done; 175 | } 176 | } 177 | 178 | ret = 0; 179 | done: 180 | fclose(fp); 181 | 182 | return ret; 183 | 184 | } 185 | 186 | int 187 | nat_parse_rules(struct zone_cfg *zone) 188 | { 189 | char path[MAX_FILE_PATH]; 190 | int ret; 191 | 192 | if ((ret = init_ip_nat(zone)) != 0) { 193 | RTE_LOG(DEBUG, USER1, 194 | "Could not initialize NAT tables for zone %s.\n", 195 | zone->name); 196 | return ret; 197 | } 198 | snprintf(path, sizeof(path), "%s/%s.nat.ip.rules", 199 | RULE_PATH, zone->name); 200 | if ((ret = parse_ip_nat(path, zone, parse_ip_nat_rule)) != 0) { 201 | RTE_LOG(DEBUG, USER1, 202 | "Could not open NAT definitions file for zone %s " 203 | "(%s): %s.\n", zone->name, path, strerror(errno)); 204 | return ret; 205 | } 206 | return ret; 207 | } 208 | -------------------------------------------------------------------------------- /dpdk/firewall/nat.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef NAT_H_ 31 | #define NAT_H_ 32 | 33 | #include 34 | 35 | #include "main.h" 36 | #include "zone.h" 37 | #include "acl.h" 38 | 39 | static inline uint32_t * 40 | get_ip_addr(struct ipv4_hdr *hdr, uint32_t type) 41 | { 42 | if (type & ACL_ACTION_SNAT) { 43 | return &hdr->src_addr; 44 | } else if (type & ACL_ACTION_DNAT) { 45 | return &hdr->dst_addr; 46 | } else { 47 | return NULL; 48 | } 49 | } 50 | 51 | static inline 52 | void 53 | nat_ip_addr(uint32_t *addr, int32_t ret, uint32_t *ipaddrs) 54 | { 55 | if (unlikely(ret == -1)) { 56 | return; 57 | } 58 | *addr = ipaddrs[ret]; 59 | } 60 | 61 | static inline 62 | void 63 | nat_ip_pkt(struct rte_mbuf *m, struct rte_hash *ht, uint32_t *ipaddrs, 64 | uint32_t type) 65 | { 66 | struct ipv4_hdr *hdr; 67 | uint32_t *addr; 68 | int32_t ret; 69 | 70 | PKT_IP_HDR(m, hdr); 71 | addr = get_ip_addr(hdr, type); 72 | if (unlikely(addr == NULL)) { 73 | return; 74 | } 75 | ret = rte_hash_lookup(ht, addr); 76 | nat_ip_addr(addr, ret, ipaddrs); 77 | PKT_IP_TX_OFFLOAD(m); 78 | } 79 | 80 | static inline 81 | void 82 | nat_ip_4pkts(struct rte_mbuf *m[4], struct rte_hash *ht, uint32_t *ipaddrs, 83 | uint32_t type[4]) 84 | { 85 | struct ipv4_hdr *hdrs[4]; 86 | uint32_t *addrs[4]; 87 | int32_t ret[4]; 88 | 89 | PKT_IP_HDR(m[0], hdrs[0]); 90 | PKT_IP_HDR(m[1], hdrs[1]); 91 | PKT_IP_HDR(m[2], hdrs[2]); 92 | PKT_IP_HDR(m[3], hdrs[3]); 93 | 94 | addrs[0] = get_ip_addr(hdrs[0], type[0]); 95 | addrs[1] = get_ip_addr(hdrs[1], type[1]); 96 | addrs[2] = get_ip_addr(hdrs[2], type[2]); 97 | addrs[3] = get_ip_addr(hdrs[3], type[3]); 98 | 99 | rte_hash_lookup_multi(ht, (const void **)&addrs[0], 4, ret); 100 | 101 | nat_ip_addr(addrs[0], ret[0], ipaddrs); 102 | nat_ip_addr(addrs[1], ret[1], ipaddrs); 103 | nat_ip_addr(addrs[2], ret[2], ipaddrs); 104 | nat_ip_addr(addrs[3], ret[3], ipaddrs); 105 | 106 | PKT_IP_TX_OFFLOAD(m[0]); 107 | PKT_IP_TX_OFFLOAD(m[1]); 108 | PKT_IP_TX_OFFLOAD(m[2]); 109 | PKT_IP_TX_OFFLOAD(m[3]); 110 | } 111 | 112 | int nat_parse_rules(struct zone_cfg *); 113 | void nat_free_rules(struct zone_cfg *); 114 | 115 | #endif /* NAT_H_ */ 116 | -------------------------------------------------------------------------------- /dpdk/firewall/packet.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | 32 | #include 33 | 34 | #include "main.h" 35 | #include "runtime.h" 36 | #include "packet.h" 37 | 38 | inline uint32_t 39 | pkt_type(struct rte_mbuf *m) 40 | { 41 | const uint8_t *payload; 42 | const struct ether_hdr *eth_hdr; 43 | uint16_t etype; 44 | uint8_t i; 45 | 46 | payload = rte_pktmbuf_mtod(m, uint8_t *); 47 | if (unlikely(payload == NULL)) { 48 | return 0; 49 | } 50 | eth_hdr = (const struct ether_hdr *)payload; 51 | etype = _ntohs(eth_hdr->ether_type); 52 | for (i = 0; i < 2; i++) { 53 | switch (etype) { 54 | case ETHER_TYPE_IPv4: 55 | m->packet_type |= RTE_PTYPE_L3_IPV4; 56 | return m->packet_type; 57 | case ETHER_TYPE_IPv6: 58 | m->packet_type |= RTE_PTYPE_L3_IPV6; 59 | return m->packet_type; 60 | case ETHER_TYPE_ARP: 61 | m->packet_type |= RTE_PTYPE_L2_ETHER_ARP; 62 | return m->packet_type; 63 | case ETHER_TYPE_RARP: 64 | m->packet_type |= RTE_PTYPE_L2_ETHER_ARP; 65 | return m->packet_type; 66 | case ETHER_TYPE_VLAN: 67 | RTE_LOG( 68 | WARNING, 69 | USER1, 70 | "Found a tagged frame. Ensure that vlan offloading " 71 | "is enabled.\n"); 72 | 73 | /* Skip over the VLAN tag */ 74 | etype = _ntohs(*(ð_hdr->ether_type + 2)); 75 | break; 76 | default: 77 | //RTE_LOG(WARNING, USER1, "Unknown: 0x%.4x\n", etype); 78 | return m->packet_type; 79 | } 80 | } 81 | 82 | RTE_LOG(WARNING, USER1, "Error determining packet type.\n"); 83 | return m->packet_type; 84 | } 85 | 86 | const struct ether_arp * 87 | pkt_ether_arp_hdr(const struct rte_mbuf *m, const uint8_t *data) 88 | { 89 | const struct arphdr *ar; 90 | size_t hlen, dlen; 91 | 92 | /* Ensure that both ethernet and ARP headers exist */ 93 | dlen = rte_pktmbuf_data_len(m); 94 | hlen = sizeof(struct ether_hdr) + sizeof(struct arphdr); 95 | if (dlen < hlen || !rte_pktmbuf_is_contiguous(m)) { 96 | return NULL; 97 | } 98 | ar = (const struct arphdr *)(data + sizeof(struct ether_hdr)); 99 | if (_ntohs(ar->ar_hrd) != ARPHRD_ETHER) { 100 | return NULL; 101 | } 102 | /* Rest of ARP packet: hardware and protocol addresses */ 103 | /* 104 | * XXX: does a buffer overflow exist here? we are trusting user 105 | * input. Later we cast the data buffer to an ether arp struct 106 | */ 107 | hlen += 2 * (ar->ar_hln + ar->ar_pln); 108 | if (dlen < hlen || _ntohs(ar->ar_pro) != ETHER_TYPE_IPv4) { 109 | return NULL; 110 | } 111 | return (const struct ether_arp *)ar; 112 | } 113 | 114 | /* 115 | * This function trusts the input parameters, i.e., the packet has a valid 116 | * IPv4 header. 117 | * This should not be a problem. We check the NIC's offload flags, and its value 118 | * should be trustworthy. 119 | * 120 | * TODO: check that the assumptions are valid. 121 | * 122 | * On 10Gbps NICs this might be true. It does not seem so on 1Gbps NICs. 123 | * 124 | */ 125 | const struct ipv4_hdr * 126 | pkt_ip_hdr(struct rte_mbuf *m, const uint8_t *data) 127 | { 128 | if (unlikely(PKT_TYPE(m) != RTE_PTYPE_L3_IPV4)) { 129 | return NULL; 130 | } 131 | return (const struct ipv4_hdr *)(data + sizeof(struct ether_hdr)); 132 | } 133 | 134 | void 135 | pkt_dump(const struct rte_mbuf *m, const char *prefix) 136 | { 137 | struct ether_hdr *eh; 138 | uint8_t *data, proto; 139 | char saddr[INET6_ADDRSTRLEN], daddr[INET6_ADDRSTRLEN]; 140 | char smac[ETHER_ADDR_FMT_SIZE], dmac[ETHER_ADDR_FMT_SIZE]; 141 | 142 | data = rte_pktmbuf_mtod(m, uint8_t *); 143 | eh = (struct ether_hdr *)data; 144 | 145 | if (likely(m->packet_type & RTE_PTYPE_L3_IPV4)) { 146 | struct ipv4_hdr *ip; 147 | ip = (struct ipv4_hdr *)(data + sizeof(struct ether_hdr)); 148 | inet_ntop(AF_INET, &ip->src_addr, saddr, sizeof(saddr)); 149 | inet_ntop(AF_INET, &ip->dst_addr, daddr, sizeof(daddr)); 150 | proto = ip->next_proto_id; 151 | } else { 152 | struct ipv6_hdr *ip; 153 | ip = (struct ipv6_hdr *)(data + sizeof(struct ether_hdr)); 154 | inet_ntop(AF_INET6, &ip->src_addr, saddr, sizeof(saddr)); 155 | inet_ntop(AF_INET6, &ip->dst_addr, daddr, sizeof(daddr)); 156 | proto = ip->proto; 157 | } 158 | ether_format_addr(smac, sizeof(smac), &eh->s_addr); 159 | ether_format_addr(dmac, sizeof(dmac), &eh->d_addr); 160 | 161 | RTE_LOG(DEBUG, USER1, 162 | "%s iface: %d. vlan: %u, etype: 0x%02x%02x, " 163 | "smac: %s, dmac: %s, saddr: %s, " 164 | "daddr: %s, protocol: 0x%02x\n", 165 | prefix, m->port, m->vlan_tci, 166 | ((uint8_t *)&eh->ether_type)[0], 167 | ((uint8_t *)&eh->ether_type)[1], 168 | smac, dmac, saddr, daddr, 169 | proto); 170 | } 171 | 172 | size_t 173 | pkt_add_vlan_hdr(struct rte_mbuf *m) 174 | { 175 | size_t size; 176 | uint8_t *data; 177 | 178 | data = rte_pktmbuf_mtod(m, uint8_t *); 179 | size = rte_pktmbuf_data_len(m); 180 | 181 | if (PKT_VLANID(m->vlan_tci) != 0) { 182 | struct ether_hdr *eh; 183 | struct vlan_hdr *vh; 184 | uint8_t *hole; 185 | size_t dlen; 186 | 187 | /* Make room for the vlan tag */ 188 | hole = data + sizeof(struct ether_hdr); 189 | dlen = size - sizeof(struct ether_hdr); 190 | memmove(hole + sizeof(struct vlan_hdr), hole, dlen); 191 | 192 | /* Place the tag */ 193 | eh = (struct ether_hdr *)data; 194 | vh = (struct vlan_hdr *)hole; 195 | vh->eth_proto = eh->ether_type; 196 | eh->ether_type = _htons(ETHER_TYPE_VLAN); 197 | vh->vlan_tci = _htons(m->vlan_tci); 198 | 199 | m->data_len += sizeof(struct vlan_hdr); 200 | m->pkt_len += sizeof(struct vlan_hdr); 201 | size += sizeof(struct vlan_hdr); 202 | } 203 | return size; 204 | } 205 | -------------------------------------------------------------------------------- /dpdk/firewall/packet.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | /* 31 | * Copyright (c) 1986, 1993 32 | * The Regents of the University of California. All rights reserved. 33 | * 34 | * Redistribution and use in source and binary forms, with or without 35 | * modification, are permitted provided that the following conditions 36 | * are met: 37 | * 1. Redistributions of source code must retain the above copyright 38 | * notice, this list of conditions and the following disclaimer. 39 | * 2. Redistributions in binary form must reproduce the above copyright 40 | * notice, this list of conditions and the following disclaimer in the 41 | * documentation and/or other materials provided with the distribution. 42 | * 3. Neither the name of the University nor the names of its contributors 43 | * may be used to endorse or promote products derived from this software 44 | * without specific prior written permission. 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 47 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 48 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 50 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 51 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 52 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 53 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 54 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56 | * SUCH DAMAGE. 57 | * 58 | * @(#)if_arp.h 8.1 (Berkeley) 6/10/93 59 | */ 60 | 61 | #ifndef _PACKET_H_ 62 | #define _PACKET_H_ 63 | 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | 72 | #include 73 | #include 74 | #include 75 | #include 76 | #include 77 | 78 | /* 79 | * Address Resolution Protocol. 80 | * 81 | * See RFC 826 for protocol description. ARP packets are variable 82 | * in size; the arp_hdr structure defines the fixed-length portion. 83 | * Protocol type values are the same as those for 10 Mb/s Ethernet. 84 | * It is followed by the variable-sized fields ar_sha, arp_spa, 85 | * arp_tha and arp_tpa in that order, according to the lengths 86 | * specified. Field names used correspond to RFC 826. 87 | */ 88 | struct arphdr { 89 | uint16_t ar_hrd; /* format of hardware address */ 90 | #define ARPHRD_ETHER 1 /* ethernet hardware format */ 91 | #define ARPHRD_IEEE802 6 /* IEEE 802 hardware format */ 92 | #define ARPHRD_FRELAY 15 /* frame relay hardware format */ 93 | #define ARPHRD_IEEE1394 24 /* IEEE 1394 (FireWire) hardware format */ 94 | uint16_t ar_pro; /* format of protocol address */ 95 | uint8_t ar_hln; /* length of hardware address */ 96 | uint8_t ar_pln; /* length of protocol address */ 97 | uint16_t ar_op; /* one of: */ 98 | #define ARPOP_REQUEST 1 /* request to resolve address */ 99 | #define ARPOP_REPLY 2 /* response to previous request */ 100 | #define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ 101 | #define ARPOP_REVREPLY 4 /* response giving protocol address */ 102 | #define ARPOP_INVREQUEST 8 /* request to identify peer */ 103 | #define ARPOP_INVREPLY 9 /* response identifying peer */ 104 | /* 105 | * The remaining fields are variable in size, 106 | * according to the sizes above. 107 | */ 108 | #ifdef COMMENT_ONLY 109 | uint8_t ar_sha[]; /* sender hardware address */ 110 | uint8_t ar_spa[]; /* sender protocol address */ 111 | uint8_t ar_tha[]; /* target hardware address */ 112 | uint8_t ar_tpa[]; /* target protocol address */ 113 | #endif 114 | } __attribute__((__packed__)); 115 | 116 | 117 | /* 118 | * Ethernet Address Resolution Protocol. 119 | * 120 | * See RFC 826 for protocol description. Structure below is adapted 121 | * to resolving internet addresses. Field names used correspond to 122 | * RFC 826. 123 | */ 124 | struct ether_arp { 125 | struct arphdr ea_hdr; /* fixed-size header */ 126 | struct ether_addr arp_sha; /* sender hardware address */ 127 | uint8_t arp_spa[4]; /* sender protocol address */ 128 | struct ether_addr arp_tha; /* target hardware address */ 129 | uint8_t arp_tpa[4]; /* target protocol address */ 130 | } __attribute__((__packed__)); 131 | 132 | #define arp_hrd ea_hdr.ar_hrd 133 | #define arp_pro ea_hdr.ar_pro 134 | #define arp_hln ea_hdr.ar_hln 135 | #define arp_pln ea_hdr.ar_pln 136 | #define arp_op ea_hdr.ar_op 137 | 138 | 139 | /* 140 | * RTE packet type identifiers 141 | */ 142 | #define PKT_RX_IP_HDR (PKT_RX_IPV4_HDR | PKT_RX_IPV6_HDR) 143 | 144 | /* 145 | * Packet metadata 146 | */ 147 | #define PKT_META_OL_IP (1 << 1) 148 | #define PKT_META_OL_IP6 (1 << 2) 149 | #define PKT_META_OL (PKT_META_OL_IP|PKT_META_OL_IP6) 150 | #define PKT_META_ROUTED (1 << 3) 151 | #define PKT_META_LOCAL (1 << 4) 152 | #define PKT_META_VLAN_TAG (1 << 5) 153 | #define PKT_META_SYNAUTH_IP (1 << 6) 154 | #define PKT_META_SYNAUTH_IP6 (1 << 7) 155 | #define PKT_META_SYNAUTH (PKT_META_OL_IP|PKT_META_OL_IP6) 156 | #define PKT_META_PARSED (1 << 8) 157 | #define PKT_META_ALT_HDR (1 << 9) 158 | 159 | 160 | /* 161 | * TCP 162 | */ 163 | #define TH_FIN 0x01 164 | #define TH_SYN 0x02 165 | #define TH_RST 0x04 166 | #define TH_PUSH 0x08 167 | #define TH_ACK 0x10 168 | #define TH_URG 0x20 169 | #define TH_ECE 0x40 170 | #define TH_CWR 0x80 171 | #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) 172 | 173 | /* 174 | * SCTP 175 | */ 176 | struct sctphdr { 177 | uint16_t src_port; /* source port */ 178 | uint16_t dest_port; /* destination port */ 179 | uint32_t v_tag; /* verification tag of packet */ 180 | uint32_t checksum; /* Adler32 C-Sum */ 181 | /* chunks follow... */ 182 | } __attribute__((__packed__)); 183 | 184 | 185 | /* 186 | * PIM 187 | */ 188 | struct pim { 189 | #ifdef __PIM_VT 190 | uint8_t pim_vt; /* PIM version and message type */ 191 | #else /* ! _PIM_VT */ 192 | #if __BYTE_ORDER == __BIG_ENDIAN 193 | u_int pim_vers:4, /* PIM protocol version */ 194 | pim_type:4; /* PIM message type */ 195 | #endif 196 | #if __BYTE_ORDER == __LITTLE_ENDIAN 197 | u_int pim_type:4, /* PIM message type */ 198 | pim_vers:4; /* PIM protocol version */ 199 | #endif 200 | #endif /* ! _PIM_VT */ 201 | uint8_t pim_reserved; /* Reserved */ 202 | uint16_t pim_cksum; /* IP-style checksum */ 203 | }; 204 | 205 | /* VLAN header */ 206 | struct vlan_ethhdr { 207 | struct ether_addr d_addr; 208 | struct ether_addr s_addr; 209 | uint16_t vlan_proto; 210 | uint16_t vlan_tci; 211 | uint16_t enc_etype; 212 | } __attribute__((__packed__)); 213 | 214 | 215 | struct mbuf_extra { 216 | uint8_t *l4hdr; 217 | uint8_t hdrs[]; 218 | }; 219 | 220 | #define L4_HDR_LEN 60 221 | 222 | #define _ntohs rte_bswap16 223 | #define _htons rte_bswap16 224 | #define _ntohl rte_bswap32 225 | #define _htonl rte_bswap32 226 | 227 | #define IP_HDR_LEN 20 228 | #define IP_PKT_MIN_LEN ETHER_HDR_LEN + IP_HDR_LEN + L4_HDR_LEN 229 | 230 | #ifndef IPPROTO_OSPFIGP 231 | #define IPPROTO_OSPFIGP 89 232 | #endif 233 | 234 | #ifndef IPPROTO_IPV4 235 | #define IPPROTO_IPV4 4 236 | #endif 237 | 238 | #define PKT_IP_HDR_LEN(hdr) (((hdr)->version_ihl & 0x0f) << 2) 239 | #define PKT_VLANID(vlan_tci) (vlan_tci & 0x0fff) 240 | 241 | #define PKT_IP_HDR(m, hdr) \ 242 | do { \ 243 | (hdr) = (struct ipv4_hdr *) \ 244 | (rte_pktmbuf_mtod((m), uint8_t *) + \ 245 | sizeof(struct ether_hdr)); \ 246 | } while (0) 247 | 248 | #define PKT_IP_TX_OFFLOAD(m) \ 249 | do { \ 250 | uint8_t *data; \ 251 | data = rte_pktmbuf_mtod(m, uint8_t *); \ 252 | data += sizeof(struct ether_hdr); \ 253 | ((struct ipv4_hdr *)data)->hdr_checksum = 0; \ 254 | m->ol_flags |= PKT_TX_IP_CKSUM; \ 255 | m->ol_flags |= PKT_TX_IPV4; \ 256 | m->l2_len = sizeof(struct ether_hdr); \ 257 | m->l3_len = sizeof(struct ipv4_hdr); \ 258 | } while (0) 259 | 260 | #define PKT_TCP_IP_TX_OFFLOAD(m, th) \ 261 | do { \ 262 | struct ipv4_hdr *ih; \ 263 | ih = rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr)); \ 264 | m->ol_flags |= PKT_TX_IP_CKSUM; \ 265 | m->ol_flags |= PKT_TX_IPV4; \ 266 | m->ol_flags |= PKT_TX_TCP_CKSUM; \ 267 | ih->hdr_checksum = 0; \ 268 | th->cksum = rte_ipv4_phdr_cksum(ih, m->ol_flags); \ 269 | m->l2_len = sizeof(struct ether_hdr); \ 270 | m->l3_len = PKT_IP_HDR_LEN(ih); \ 271 | } while (0) 272 | 273 | #define PKT_TYPE(m) \ 274 | ((m) ? \ 275 | (m)->packet_type ? \ 276 | (m)->packet_type \ 277 | : \ 278 | pkt_type(m) \ 279 | : \ 280 | 0) \ 281 | 282 | #define PKT_ETH_ADDR_SWAP(hdr) \ 283 | do { \ 284 | struct ether_addr addr; \ 285 | ether_addr_copy(&hdr->s_addr, &addr); \ 286 | ether_addr_copy(&hdr->d_addr, &hdr->s_addr); \ 287 | ether_addr_copy(&addr, &hdr->d_addr); \ 288 | } while (0) 289 | 290 | /* 291 | * We only need this if the NIC does not set the packet type. 292 | * This is the case with e1000 cards. 293 | */ 294 | #define PKT_INIT(m) \ 295 | do { \ 296 | (m)->packet_type = 0; \ 297 | (m)->udata64 = 0; \ 298 | } while (0) 299 | 300 | #define PKT_FREE(m) \ 301 | do { \ 302 | (m)->packet_type = 0; \ 303 | (m)->udata64 = 0; \ 304 | rte_pktmbuf_free((m)); \ 305 | } while (0) 306 | 307 | static inline uint32_t 308 | ip_hash_crc(const void *data, __rte_unused uint32_t datalen, uint32_t initval) 309 | { 310 | const uint32_t *ip; 311 | 312 | ip = data; 313 | 314 | #ifdef RTE_MACHINE_CPUFLAG_SSE4_2 315 | initval = rte_hash_crc_4byte(*ip, initval); 316 | #else /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 317 | initval = rte_jhash_1word(*ip, initval); 318 | #endif /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 319 | 320 | return initval; 321 | } 322 | 323 | static inline uint32_t 324 | ip6_hash_crc(const void *data, __rte_unused uint32_t datalen, uint32_t initval) 325 | { 326 | 327 | #ifdef RTE_MACHINE_CPUFLAG_SSE4_2 328 | initval = rte_hash_crc(data, sizeof(struct in6_addr), initval); 329 | #else /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 330 | initval = rte_jhash(data, sizeof(struct in6_addr), initval); 331 | #endif /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 332 | 333 | return initval; 334 | } 335 | 336 | static inline uint32_t 337 | data_hash_crc(const void *data, uint32_t datalen, uint32_t initval) 338 | { 339 | 340 | #ifdef RTE_MACHINE_CPUFLAG_SSE4_2 341 | initval = rte_hash_crc(data, datalen, initval); 342 | #else /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 343 | initval = rte_jhash(data, datalen, initval); 344 | #endif /* RTE_MACHINE_CPUFLAG_SSE4_2 */ 345 | 346 | return initval; 347 | } 348 | 349 | static inline void * 350 | ip_l4_hdr(struct rte_mbuf *m) 351 | { 352 | /* XXX: assumes that the IP header has no options */ 353 | return rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr) + 354 | sizeof(struct ipv4_hdr)); 355 | } 356 | 357 | static inline void * 358 | ip6_l4_hdr(struct rte_mbuf *m) 359 | { 360 | assert(m->udata64 & PKT_META_PARSED); 361 | 362 | if (unlikely(m->udata64 & PKT_META_ALT_HDR)) { 363 | struct mbuf_extra *me; 364 | 365 | me = rte_pktmbuf_mtod_offset(m, struct mbuf_extra *, 366 | m->data_len); 367 | 368 | return me->l4hdr; 369 | } 370 | 371 | return rte_pktmbuf_mtod_offset(m, void *, 372 | sizeof(struct ether_addr) + sizeof(struct ipv6_hdr)); 373 | } 374 | 375 | inline uint32_t pkt_type(struct rte_mbuf *m); 376 | const struct ether_arp * 377 | pkt_ether_arp_hdr(const struct rte_mbuf *, const uint8_t *); 378 | const struct ipv4_hdr *pkt_ip_hdr(struct rte_mbuf *, const uint8_t *); 379 | void pkt_dump(const struct rte_mbuf *, const char *); 380 | size_t pkt_add_vlan_hdr(struct rte_mbuf *); 381 | 382 | #endif /* PACKET_H_ */ 383 | -------------------------------------------------------------------------------- /dpdk/firewall/rollhash.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef ROLLHASH_H_ 31 | #define ROLLHASH_H_ 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #define HASH_TTL_US 60 * US_PER_S 40 | 41 | struct transient_hash { 42 | struct rte_hash *h; 43 | uint64_t ttl; 44 | }; 45 | 46 | struct rollhash { 47 | struct transient_hash cur; 48 | struct transient_hash old; 49 | }; 50 | 51 | 52 | static inline int 53 | rh_create(struct rollhash *rh, struct rte_hash_parameters *p) 54 | { 55 | struct rte_hash *tables[2]; 56 | const char *orig_name; 57 | char name[64]; 58 | int i, rc; 59 | 60 | rc = -1; 61 | orig_name = p->name; 62 | p->name = name; 63 | 64 | /* Ensure the sum of internal entries matches the requested count */ 65 | p->entries /= 2; 66 | 67 | for (i = 0; i < 2; i++) { 68 | snprintf(name, sizeof(name), "%s_%d", orig_name, i); 69 | tables[i] = rte_hash_create(p); 70 | if (tables[i] == NULL) { 71 | goto done; 72 | } 73 | } 74 | 75 | rc = 0; 76 | rh->old.h = tables[0]; 77 | rh->cur.h = tables[1]; 78 | 79 | done: 80 | if (rc < 0) { 81 | if (tables[0] != NULL) 82 | rte_hash_free(tables[0]); 83 | if (tables[1] != NULL) 84 | rte_hash_free(tables[1]); 85 | } 86 | return rc; 87 | } 88 | 89 | static inline int 90 | rh_add_key_data(struct rollhash *rh, const void *key, void *data, 91 | uint64_t now_us) 92 | { 93 | struct rte_hash *tmp; 94 | int32_t rc; 95 | 96 | rc = rte_hash_add_key_data(rh->cur.h, key, data); 97 | if (likely(rc == 0)) { 98 | rh->cur.ttl = now_us + HASH_TTL_US; 99 | return rc; 100 | } 101 | /* Check if previous hash table may still have valid entries */ 102 | if (rh->old.ttl < now_us) { 103 | return rc; 104 | } 105 | /* Roll-over hashtables */ 106 | tmp = rh->cur.h; 107 | 108 | rte_hash_reset(rh->old.h); 109 | rh->cur.h = rh->old.h; 110 | 111 | rh->old.h = tmp; 112 | rh->old.ttl = rh->cur.ttl; 113 | 114 | rh->cur.ttl = now_us + HASH_TTL_US; 115 | rc = rte_hash_add_key_data(rh->cur.h, key, data); 116 | 117 | return rc; 118 | } 119 | 120 | static inline int 121 | rh_lookup_data(struct rollhash *rh, const void *key, void **data) 122 | { 123 | int rc; 124 | 125 | rc = rte_hash_lookup_data(rh->cur.h, key, data); 126 | if (rc == 0) { 127 | return rc; 128 | } 129 | return rte_hash_lookup_data(rh->old.h, key, data); 130 | } 131 | 132 | #endif /* ROLLHASH_H_ */ 133 | -------------------------------------------------------------------------------- /dpdk/firewall/routing.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef ROUTING_H_ 31 | #define ROUTING_H_ 32 | 33 | #include 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include "main.h" 50 | #include "util.h" 51 | #include "packet.h" 52 | 53 | static struct ether_addr nullea; 54 | 55 | static inline int 56 | __attribute__((always_inline)) 57 | rt_is_local(struct rte_mbuf *m) 58 | { 59 | uint8_t *data; 60 | uint16_t vlan; 61 | int is_local; 62 | 63 | data = rte_pktmbuf_mtod(m, uint8_t *); 64 | vlan = PKT_VLANID(m->vlan_tci); 65 | is_local = 0; 66 | 67 | if (m->packet_type & RTE_PTYPE_L3_IPV4) { 68 | struct ipv4_hdr *ih; 69 | 70 | ih = (struct ipv4_hdr *)(data + sizeof(struct ether_hdr)); 71 | is_local = (ih->dst_addr & cfg.vlans[vlan].ip_mask.s_addr) == 72 | cfg.vlans[vlan].ip_net.s_addr; 73 | } else if (m->packet_type & RTE_PTYPE_L3_IPV6) { 74 | struct ipv6_hdr *ih; 75 | __m128i addr, net; 76 | 77 | ih = (struct ipv6_hdr *)(data + sizeof(struct ether_hdr)); 78 | addr = _mm_loadu_si128((__m128i *) & ih->dst_addr); 79 | net = _mm_and_si128(addr, cfg.vlans[vlan].ip6_mask.xmm); 80 | is_local = is_equal128(net, cfg.vlans[vlan].ip6_net.xmm); 81 | } else { 82 | is_local = 1; 83 | } 84 | 85 | /* 86 | * TODO: handle broadcast and multicast packets 87 | */ 88 | return is_local; 89 | } 90 | 91 | #define FLOW_VLAN_OUT 0 92 | #define FLOW_VLAN_IN 1 93 | 94 | static inline void 95 | rt_refresh_gws(struct rt_ctx *ctx) 96 | { 97 | struct ether_addr *macs; 98 | uint16_t n_gws; 99 | int i; 100 | 101 | macs = ctx->igws; 102 | n_gws = 0; 103 | for (i = 0; i < cfg.n_igws; i++) { 104 | if (memcmp(&cfg.igws[i].mac, &macs[i], 105 | sizeof(struct ether_addr))) { 106 | ether_addr_copy(&cfg.igws[i].mac, &macs[i]); 107 | } 108 | if (memcmp(&macs[i], &nullea, sizeof(nullea)) != 0) { 109 | n_gws++; 110 | } 111 | } 112 | ctx->n_igws = n_gws; 113 | 114 | macs = ctx->ogws; 115 | n_gws = 0; 116 | for (i = 0; i < cfg.n_ogws; i++) { 117 | if (memcmp(&cfg.ogws[i].mac, &macs[i], 118 | sizeof(struct ether_addr))) { 119 | ether_addr_copy(&cfg.ogws[i].mac, &macs[i]); 120 | } 121 | if (memcmp(&macs[i], &nullea, sizeof(nullea)) != 0) { 122 | n_gws++; 123 | } 124 | } 125 | ctx->n_ogws = n_gws; 126 | 127 | LOG(DEBUG, USER1, "Updating gateway mac addresses.\n"); 128 | ctx->ovlan = cfg.ovlan; 129 | ctx->gws_ts = cfg.gws_ts; 130 | } 131 | 132 | static inline 133 | __attribute__((always_inline)) 134 | uint64_t 135 | hash_pkt(struct rte_mbuf *m, struct ether_hdr *eh, uint8_t flow) 136 | { 137 | uint64_t r; 138 | 139 | r = 0; 140 | 141 | if (PKT_TYPE(m) == RTE_PTYPE_L3_IPV4) { 142 | struct ipv4_hdr *iph = (struct ipv4_hdr *)(eh + 1); 143 | 144 | if (flow == FLOW_VLAN_OUT) { 145 | r = rte_hash_crc_4byte(iph->src_addr, 0); 146 | } else { 147 | r = rte_hash_crc_4byte(iph->dst_addr, 0); 148 | } 149 | } else { 150 | struct ipv6_hdr *iph = (struct ipv6_hdr *)(eh + 1); 151 | uint64_t *p; 152 | 153 | if (flow == FLOW_VLAN_OUT) { 154 | p = (uint64_t *)(&(iph->src_addr) + 8); 155 | r = rte_hash_crc_8byte(*p, 0); 156 | } else { 157 | p = (uint64_t *)(&(iph->dst_addr) + 8); 158 | r = rte_hash_crc_8byte(*p, 8); 159 | } 160 | } 161 | 162 | return r; 163 | } 164 | 165 | static inline 166 | __attribute__((always_inline)) 167 | struct ether_addr * 168 | rt_select_gw(struct rte_mbuf *m, struct ether_hdr *eh, 169 | struct rt_ctx *ctx) 170 | { 171 | if (PKT_VLANID(m->vlan_tci) == ctx->ovlan) { 172 | uint64_t slot = hash_pkt(m, eh, FLOW_VLAN_OUT); 173 | if (unlikely(ctx->n_ogws == 0)) { 174 | /* No gateways available yet. Drop the packet... */ 175 | rte_pktmbuf_free(m); 176 | return NULL; 177 | } 178 | 179 | slot %= ctx->n_ogws; 180 | return &ctx->ogws[slot]; 181 | 182 | } else { 183 | uint64_t slot = hash_pkt(m, eh, FLOW_VLAN_IN); 184 | if (unlikely(ctx->n_igws == 0)) { 185 | /* No gateways available yet. Drop the packet... */ 186 | rte_pktmbuf_free(m); 187 | return NULL; 188 | } 189 | 190 | slot %= ctx->n_igws; 191 | return &ctx->igws[slot]; 192 | } 193 | } 194 | 195 | #endif /* ROUTING_H_ */ 196 | -------------------------------------------------------------------------------- /dpdk/firewall/runtime.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include "main.h" 31 | #include "util.h" 32 | #include "runtime.h" 33 | 34 | void 35 | wrk_pkt_stats(struct worker_lc_cfg *lp, uint64_t *last_stats) 36 | { 37 | uint32_t i; 38 | uint64_t elapsed_us; 39 | 40 | elapsed_us = TSC2US(now_tsc - *last_stats); 41 | if (elapsed_us < TASK_STATS_US) { 42 | return; 43 | } 44 | for (i = 0; i < lp->n_irings; i++) { 45 | uint64_t pps; 46 | 47 | if (lp->irings_pkts[i] == 0) { 48 | continue; 49 | } 50 | pps = lp->irings_pkts[i] / (elapsed_us / US_PER_S); 51 | lp->irings_pkts[i] = 0; 52 | 53 | RTE_LOG( 54 | DEBUG, 55 | USER1, 56 | "Worker %u: input ring %" PRIu32 57 | " stats: %" PRIu64 " pps\n", lp->id, i, pps); 58 | } 59 | 60 | for (i = 0; i < lp->n_crings; i++) { 61 | uint64_t pps; 62 | 63 | if (lp->crings_pkts[i] == 0) { 64 | continue; 65 | } 66 | pps = lp->crings_pkts[i] / (elapsed_us / US_PER_S); 67 | lp->crings_pkts[i] = 0; 68 | 69 | RTE_LOG( 70 | DEBUG, 71 | USER1, 72 | "Worker %u: control ring %" PRIu32 73 | " stats: %" PRIu64 " pps\n", lp->id, i, pps); 74 | } 75 | 76 | *last_stats = now_tsc; 77 | } 78 | 79 | int 80 | lcore_main_loop(__attribute__((unused)) void *arg) 81 | { 82 | struct lc_cfg *lp; 83 | unsigned lcore; 84 | 85 | lcore = rte_lcore_id(); 86 | lp = &cfg.lcores[lcore]; 87 | tsc_per_us = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S; 88 | 89 | if (lp->type == LCORE_TYPE_IO) { 90 | RTE_LOG(DEBUG, USER1, "IO logical core %u main loop.\n", lcore); 91 | io_lcore_main_loop(lp); 92 | } else if (lp->type == LCORE_TYPE_WORKER) { 93 | RTE_LOG(DEBUG, USER1, 94 | "Worker logical core %u (type: %u) main loop.\n", 95 | lcore, 96 | (unsigned)lp->worker.type); 97 | wrk_lcore_main_loop(lp); 98 | } 99 | return 0; 100 | } 101 | -------------------------------------------------------------------------------- /dpdk/firewall/runtime.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef RUNTIME_H_ 31 | #define RUNTIME_H_ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | 49 | #include 50 | 51 | #include "zone.h" 52 | 53 | #ifndef LCORE_IO_FLUSH 54 | #define LCORE_IO_FLUSH 1000 55 | //#define LCORE_IO_FLUSH 1000000 56 | #endif 57 | 58 | #ifndef LCORE_WORKER_FLUSH 59 | #define LCORE_WORKER_FLUSH 1000 60 | //#define LCORE_WORKER_FLUSH 1000000 61 | #endif 62 | 63 | #ifndef LCORE_WORKER_TASKS 64 | #define LCORE_WORKER_TASKS 1000000 65 | //#define LCORE_WORKER_TASKS 1000000 66 | #endif 67 | 68 | #ifndef APP_STATS 69 | #define APP_STATS 1000000 70 | #endif 71 | 72 | #ifndef LCORE_WORKER_FLUSH_US 73 | #define LCORE_WORKER_FLUSH_US 100 /* Drain queues every 100 74 | * microseconds */ 75 | #endif 76 | 77 | #ifndef LCORE_WORKER_TASKS_US 78 | #define LCORE_WORKER_TASKS_US 5 * US_PER_S /* Perform tasks every 5 79 | * seconds */ 80 | #endif 81 | 82 | #ifndef LCORE_CTRL_TASKS_US 83 | #define LCORE_CTRL_TASKS_US 1 * US_PER_S 84 | #endif 85 | 86 | #define IO_RX_DROP_ALL_PACKETS 0 87 | #define WORKER_DROP_ALL_PACKETS 0 88 | #define IO_TX_DROP_ALL_PACKETS 0 89 | 90 | #ifndef IO_RX_PREFETCH_ENABLE 91 | #define IO_RX_PREFETCH_ENABLE 1 92 | #endif 93 | 94 | #ifndef WORKER_PREFETCH_ENABLE 95 | #define WORKER_PREFETCH_ENABLE 1 96 | #endif 97 | 98 | #ifndef IO_TX_PREFETCH_ENABLE 99 | #define IO_TX_PREFETCH_ENABLE 1 100 | #endif 101 | 102 | #if IO_RX_PREFETCH_ENABLE 103 | #define IO_RX_PREFETCH0(p) rte_prefetch0(p) 104 | #define IO_RX_PREFETCH1(p) rte_prefetch1(p) 105 | #else 106 | #define IO_RX_PREFETCH0(p) 107 | #define IO_RX_PREFETCH1(p) 108 | #endif 109 | 110 | #if WORKER_PREFETCH_ENABLE 111 | #define WORKER_PREFETCH0(p) rte_prefetch0(p) 112 | #define WORKER_PREFETCH1(p) rte_prefetch1(p) 113 | #else 114 | #define WORKER_PREFETCH0(p) 115 | #define WORKER_PREFETCH1(p) 116 | #endif 117 | 118 | #if IO_TX_PREFETCH_ENABLE 119 | #define IO_TX_PREFETCH0(p) rte_prefetch0(p) 120 | #define IO_TX_PREFETCH1(p) rte_prefetch1(p) 121 | #else 122 | #define IO_TX_PREFETCH0(p) 123 | #define IO_TX_PREFETCH1(p) 124 | #endif 125 | 126 | #define IDLE_COUNT_CHK 10 127 | #define IDLE_COUNT_SOFT 100 128 | #define IDLE_COUNT_HARD 250 129 | 130 | #define WORKER_REQ_RESET_CNT (1 << 1) 131 | 132 | #define TASK_REFRESH_ARP_US 1 * US_PER_S 133 | #define TASK_REFRESH_VLANS_US 10 * US_PER_S 134 | #define TASK_NEGO_LACP_US 25 * US_PER_S / MS_PER_S /* Every 25 ms */ 135 | #define TASK_STATS_US 5 * US_PER_S 136 | #define TASK_KNI_US 1 * US_PER_S 137 | 138 | extern uint64_t tsc_per_us; 139 | extern volatile uint64_t now_tsc; 140 | 141 | static inline void 142 | idle_heuristic(uint32_t idle) 143 | { 144 | if (likely(idle < IDLE_COUNT_CHK)) { 145 | return; 146 | } 147 | if (idle < IDLE_COUNT_SOFT) { 148 | rte_delay_us(idle); 149 | } else if (idle >= IDLE_COUNT_SOFT && idle < IDLE_COUNT_HARD) { 150 | usleep(IDLE_COUNT_SOFT); 151 | } else { 152 | usleep(IDLE_COUNT_HARD); 153 | } 154 | } 155 | 156 | void io_lcore_main_loop(void *); 157 | 158 | /* Worker functions */ 159 | void wrk_lcore_main_loop(void *); 160 | void fw_lcore_main_loop_cnt(struct worker_lc_cfg *); 161 | void fw_lcore_main_loop_tsc(struct worker_lc_cfg *); 162 | void kni_lcore_main_loop(struct worker_lc_cfg *); 163 | int wrk_update_arp_table(const struct rte_mbuf *, const uint8_t *); 164 | void tap_lcore_main_loop(struct worker_lc_cfg *); 165 | uint32_t tap_fwd_pkts_to_kernel(struct worker_lc_cfg *, uint32_t); 166 | uint32_t tap_fwd_pkts_to_nic(struct worker_lc_cfg *, uint32_t); 167 | uint32_t kni_fwd_pkts_to_kernel(struct worker_lc_cfg *, uint32_t); 168 | uint32_t kni_fwd_pkts_to_nic(struct worker_lc_cfg *, uint32_t); 169 | void ctrl_lcore_main_loop(struct worker_lc_cfg *); 170 | struct gw_addr *arp_chk_gw_pkt(struct rte_mbuf *, uint64_t); 171 | void arp_send_probes(struct worker_lc_cfg *, struct gw_addr *, uint32_t, 172 | uint64_t); 173 | int scan_vlans(void); 174 | void wrk_pkt_stats(struct worker_lc_cfg *, uint64_t *); 175 | 176 | #endif /* RUNTIME_H_ */ 177 | -------------------------------------------------------------------------------- /dpdk/firewall/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "strutil.h" 23 | 24 | /* 25 | * Appends src to string dst of size dsize (unlike strncat, dsize is the 26 | * full size of dst, not space left). At most dsize-1 characters 27 | * will be copied. Always NUL terminates (unless dsize <= strlen(dst)). 28 | * Returns strlen(src) + MIN(dsize, strlen(initial dst)). 29 | * If retval >= dsize, truncation occurred. 30 | */ 31 | size_t 32 | strlcat(char *dst, const char *src, size_t dsize) 33 | { 34 | const char *odst = dst; 35 | const char *osrc = src; 36 | size_t n = dsize; 37 | size_t dlen; 38 | 39 | /* Find the end of dst and adjust bytes left but don't go past end. */ 40 | while (n-- != 0 && *dst != '\0') 41 | dst++; 42 | dlen = dst - odst; 43 | n = dsize - dlen; 44 | 45 | if (n-- == 0) 46 | return (dlen + strlen(src)); 47 | while (*src != '\0') { 48 | if (n != 0) { 49 | *dst++ = *src; 50 | n--; 51 | } 52 | src++; 53 | } 54 | *dst = '\0'; 55 | 56 | return (dlen + (src - osrc)); /* count does not include NUL */ 57 | } 58 | -------------------------------------------------------------------------------- /dpdk/firewall/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include 20 | #include 21 | 22 | #include "strutil.h" 23 | 24 | /* 25 | * Copy string src to buffer dst of size dsize. At most dsize-1 26 | * chars will be copied. Always NUL terminates (unless dsize == 0). 27 | * Returns strlen(src); if retval >= dsize, truncation occurred. 28 | */ 29 | size_t 30 | strlcpy(char *dst, const char *src, size_t dsize) 31 | { 32 | const char *osrc = src; 33 | size_t nleft = dsize; 34 | 35 | /* Copy as many bytes as will fit. */ 36 | if (nleft != 0) { 37 | while (--nleft != 0) { 38 | if ((*dst++ = *src++) == '\0') 39 | break; 40 | } 41 | } 42 | /* Not enough room in dst, add NUL and traverse rest of src. */ 43 | if (nleft == 0) { 44 | if (dsize != 0) 45 | *dst = '\0'; /* NUL-terminate dst */ 46 | while (*src++); 47 | } 48 | return (src - osrc - 1); /* count does not include NUL */ 49 | } 50 | -------------------------------------------------------------------------------- /dpdk/firewall/strutil.h: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998, 2015 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #ifndef STRUTIL_H_ 20 | #define STRUTIL_H_ 21 | 22 | size_t strlcpy(char *, const char *, size_t); 23 | size_t strlcat(char *, const char *, size_t); 24 | 25 | #endif /* STRUTIL_H_ */ 26 | -------------------------------------------------------------------------------- /dpdk/firewall/synauth.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include "main.h" 39 | #include "util.h" 40 | #include "runtime.h" 41 | #include "packet.h" 42 | #include "synauth.h" 43 | 44 | #define MAXSEQ (0xffffffff) 45 | #define RCV_WINDOW (0xffff) 46 | #define COOKIE_MASK (0x0000ffff) 47 | 48 | #define MAX_ENTRIES (1 << 21) /* 2 million */ 49 | #define KEY_TTL_US (uint64_t)(1 * 60 * US_PER_S) /* 1 minutes */ 50 | #define IP_TTL_S (uint32_t)(5 * 60) /* 5 minutes */ 51 | 52 | union _entry { 53 | struct { 54 | uint32_t ttl; 55 | int32_t score; 56 | } s; 57 | void *ptr; 58 | }; 59 | 60 | #define AUTH_PKT(ctx, ih, th, r) \ 61 | do { \ 62 | (r) = data_hash_crc(&(ih)->src_addr, sizeof((ih)->src_addr) * 2, 0); \ 63 | (r) = data_hash_crc(&(th)->src_port, sizeof((th)->src_port) * 2, r); \ 64 | (r) = authenticate(ctx, &(r), sizeof(r)); \ 65 | } while (0) 66 | 67 | #define ADD_COOKIE(seq, cookie, r) \ 68 | do { \ 69 | r = (seq & ~COOKIE_MASK) | (cookie & COOKIE_MASK); \ 70 | if (r >= seq) { \ 71 | r -= (RCV_WINDOW + 1); \ 72 | } \ 73 | } while (0) 74 | 75 | #define GET_COOKIE(seq) (seq & COOKIE_MASK) 76 | 77 | static void 78 | rekey_context(struct synauth_ctx *ctx, uint64_t now) 79 | { 80 | uint64_t ttl; 81 | int keylen; 82 | 83 | ttl = TSC2US(now) + KEY_TTL_US; 84 | ttl = US2TSC(ttl); 85 | ctx->key_ttl = ttl; 86 | 87 | /* TODO: check return codes */ 88 | keylen = sizeof(ctx->key); 89 | EVP_EncryptUpdate(&ctx->cipher, ctx->key, &keylen, ctx->key, keylen); 90 | EVP_EncryptInit(&ctx->cipher, CIPHER_ALGO, ctx->key, NULL); 91 | } 92 | 93 | static inline uint32_t 94 | authenticate(struct synauth_ctx *ctx, void *data, size_t inlen) 95 | { 96 | uint8_t buf[CIPHER_BLOCK_SIZE]; 97 | uint64_t now; 98 | uint32_t *r; 99 | int outlen; 100 | 101 | assert(sizeof(buf) >= inlen); 102 | 103 | memset(buf, 0, sizeof(buf)); 104 | rte_memcpy(buf, data, inlen); 105 | now = now_tsc; 106 | 107 | if (unlikely(ctx->key_ttl > now)) { 108 | rekey_context(ctx, now); 109 | } 110 | /* XXX: check if EncryptUpdate handles negative sizes */ 111 | /* XXX: check return codes */ 112 | EVP_EncryptUpdate(&ctx->cipher, buf, &outlen, buf, sizeof(buf)); 113 | EVP_EncryptFinal(&ctx->cipher, buf + outlen, &outlen); 114 | 115 | r = (uint32_t *)(&(buf[outlen - sizeof(uint32_t)])); 116 | 117 | return *r; 118 | } 119 | 120 | static int 121 | trust_ip(struct synauth_ctx *ctx, struct ipv4_hdr *ih) 122 | { 123 | union _entry e; 124 | uint64_t now_us; 125 | uint32_t now_s; 126 | 127 | now_us = TSC2US(now_tsc); 128 | now_s = US2S(now_us); 129 | 130 | e.s.score = 0; 131 | e.s.ttl = now_s + IP_TTL_S; 132 | 133 | return rh_add_key_data(&ctx->ip_wlst, &ih->src_addr, e.ptr, now_us); 134 | } 135 | 136 | static int 137 | trust_ip6(struct synauth_ctx *ctx, struct ipv6_hdr *ih) 138 | { 139 | union _entry e; 140 | uint64_t now_us; 141 | uint32_t now_s; 142 | 143 | now_us = TSC2US(now_tsc); 144 | now_s = US2S(now_us); 145 | 146 | e.s.score = 0; 147 | e.s.ttl = now_s + IP_TTL_S; 148 | 149 | return rh_add_key_data(&ctx->ip6_wlst, &ih->src_addr, e.ptr, now_us); 150 | } 151 | 152 | static void 153 | setup_ack(struct tcp_hdr *th, uint32_t cookie) 154 | { 155 | uint32_t seq, ack; 156 | uint16_t port; 157 | 158 | port = th->src_port; 159 | th->src_port = th->dst_port; 160 | th->dst_port = port; 161 | th->cksum = 0; 162 | 163 | /* ACK an out-of-sequence initial sequence number */ 164 | th->tcp_flags |= TH_ACK; 165 | th->rx_win = _htons(RCV_WINDOW); 166 | 167 | seq = _ntohl(th->sent_seq); 168 | ack = _ntohl(th->recv_ack); 169 | ADD_COOKIE(seq, cookie, ack); 170 | 171 | /* 172 | LOG(DEBUG, USER1, "[SA] cookie: %u, GET_COOKIE(seq): %u\n", 173 | GET_COOKIE(cookie), GET_COOKIE(ack)); 174 | */ 175 | 176 | th->sent_seq = th->recv_ack - 1; 177 | th->recv_ack = _htonl(ack); 178 | } 179 | 180 | int 181 | synauth_vrfy_ip(struct synauth_ctx *ctx, struct rte_mbuf *m) 182 | { 183 | struct ipv4_hdr *ih; 184 | struct tcp_hdr *th; 185 | uint32_t seq, cookie; 186 | 187 | ih = rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr)); 188 | th = ip_l4_hdr(m); 189 | 190 | /* TCP initial seqno (srcip + dstip + srcport + dstport) */ 191 | AUTH_PKT(ctx, ih, th, cookie); 192 | seq = _ntohl(th->sent_seq); 193 | if (GET_COOKIE(seq) == GET_COOKIE(cookie)) { 194 | trust_ip(ctx, ih); 195 | return SYNAUTH_OK; 196 | } 197 | 198 | /* 199 | LOG(DEBUG, USER1, "[SA] check failed: actual: %u, expected: %u\n", 200 | GET_COOKIE(cookie), GET_COOKIE(seq)); 201 | */ 202 | return SYNAUTH_INVALID; 203 | } 204 | 205 | int 206 | synauth_vrfy_ip6(struct synauth_ctx *ctx, struct rte_mbuf *m) 207 | { 208 | struct ipv6_hdr *ih; 209 | struct tcp_hdr *th; 210 | uint32_t seq, cookie; 211 | 212 | ih = rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr)); 213 | th = ip6_l4_hdr(m); 214 | 215 | /* TCP initial seqno (srcip + dstip + srcport + dstport) */ 216 | AUTH_PKT(ctx, ih, th, cookie); 217 | seq = _ntohl(th->sent_seq); 218 | if (GET_COOKIE(seq) == GET_COOKIE(cookie)) { 219 | trust_ip6(ctx, ih); 220 | return SYNAUTH_OK; 221 | } 222 | 223 | return SYNAUTH_INVALID; 224 | } 225 | 226 | int 227 | synauth_init(struct synauth_ctx *ctx) 228 | { 229 | char name[64]; 230 | int rc; 231 | unsigned cid, sid; 232 | 233 | rc = -1; 234 | cid = rte_lcore_id(); 235 | sid = rte_socket_id(); 236 | 237 | /* IP white lists */ 238 | snprintf(name, sizeof(name), "synwl_ip_c%d_s%d", cid, sid); 239 | struct rte_hash_parameters ip_params = { 240 | .name = name, 241 | .entries = MAX_ENTRIES, 242 | .key_len = sizeof(struct in_addr), 243 | .hash_func = ip_hash_crc, 244 | .hash_func_init_val = 0, 245 | .socket_id = sid 246 | }; 247 | if ((rc = rh_create(&ctx->ip_wlst, &ip_params)) != 0) { 248 | goto done; 249 | } 250 | 251 | snprintf(name, sizeof(name), "synwl_ip6_c%d_s%d", cid, sid); 252 | struct rte_hash_parameters ip6_params = { 253 | .name = name, 254 | .entries = MAX_ENTRIES, 255 | .key_len = sizeof(struct in6_addr), 256 | .hash_func = ip6_hash_crc, 257 | .hash_func_init_val = 0, 258 | .socket_id = sid 259 | }; 260 | if ((rc = rh_create(&ctx->ip6_wlst, &ip6_params)) != 0) { 261 | goto done; 262 | } 263 | 264 | /* Crypto context */ 265 | EVP_CIPHER_CTX_init(&ctx->cipher); 266 | if (EVP_CIPHER_CTX_set_padding(&ctx->cipher, 0) != 1 || 267 | RAND_bytes(ctx->key, sizeof(ctx->key)) != 1 || 268 | EVP_EncryptInit(&ctx->cipher, CIPHER_ALGO, ctx->key, NULL) != 1) { 269 | RTE_LOG(ERR, USER1, "Could not initialize cipher context.\n"); 270 | goto done; 271 | } 272 | rc = 0; 273 | 274 | done: 275 | return rc; 276 | } 277 | 278 | int 279 | synauth_auth_ip(struct synauth_ctx *ctx, struct rte_mbuf *m) 280 | { 281 | struct ether_hdr *eh; 282 | struct ipv4_hdr *ih; 283 | struct tcp_hdr *th; 284 | uint32_t aux; 285 | 286 | eh = rte_pktmbuf_mtod(m, struct ether_hdr *); 287 | ih = (struct ipv4_hdr *)(eh + 1); 288 | th = ip_l4_hdr(m); 289 | 290 | /* TCP initial seqno (srcip + dstip + srcport + dstport) */ 291 | AUTH_PKT(ctx, ih, th, aux); 292 | setup_ack(th, aux); 293 | 294 | /* IP header */ 295 | aux = ih->src_addr; 296 | ih->src_addr = ih->dst_addr; 297 | ih->dst_addr = aux; 298 | ih->hdr_checksum = 0; 299 | 300 | /* Swap source and destination ethernet addresses */ 301 | PKT_ETH_ADDR_SWAP(eh); 302 | 303 | /* Offload checksum calculations */ 304 | PKT_TCP_IP_TX_OFFLOAD(m, th); 305 | 306 | m->udata64 |= PKT_META_ROUTED; 307 | 308 | return 0; 309 | } 310 | 311 | int 312 | synauth_auth_ip6(struct synauth_ctx *ctx, struct rte_mbuf *m) 313 | { 314 | struct ether_hdr *eh; 315 | struct ipv6_hdr *ih; 316 | struct tcp_hdr *th; 317 | struct in6_addr ipa; 318 | uint32_t aux; 319 | 320 | /* TODO: build a new packet with no header options. */ 321 | 322 | eh = rte_pktmbuf_mtod(m, struct ether_hdr *); 323 | ih = (struct ipv6_hdr *)(eh + 1); 324 | th = ip6_l4_hdr(m); 325 | 326 | /* TCP initial seqno (srcip + dstip + srcport + dstport) */ 327 | AUTH_PKT(ctx, ih, th, aux); 328 | setup_ack(th, aux); 329 | 330 | /* IP header */ 331 | rte_memcpy(&ipa.s6_addr, &ih->src_addr, sizeof(struct in6_addr)); 332 | rte_memcpy(&ih->src_addr, &ih->dst_addr, sizeof(struct in6_addr)); 333 | rte_memcpy(&ih->dst_addr, &ipa.s6_addr, sizeof(struct in6_addr)); 334 | 335 | /* Swap source and destination ethernet addresses */ 336 | PKT_ETH_ADDR_SWAP(eh); 337 | 338 | m->udata64 |= PKT_META_ROUTED; 339 | 340 | return 0; 341 | } 342 | 343 | int 344 | synauth_test_ip(struct synauth_ctx *ctx, struct rte_mbuf *m) 345 | { 346 | void *ptr; 347 | struct ipv4_hdr *ih; 348 | 349 | ih = rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr)); 350 | 351 | if (rh_lookup_data(&ctx->ip_wlst, &ih->src_addr, &ptr) == 0) { 352 | union _entry e; 353 | uint32_t now = US2S(TSC2US(now_tsc)); 354 | e.ptr = ptr; 355 | 356 | if (likely(e.s.ttl > now)) { 357 | return SYNAUTH_OK; 358 | } 359 | } 360 | 361 | return SYNAUTH_IP_AUTH; 362 | } 363 | 364 | 365 | int 366 | synauth_test_ip6(struct synauth_ctx *ctx, struct rte_mbuf *m) 367 | { 368 | void *ptr; 369 | struct ipv6_hdr *ih; 370 | 371 | ih = rte_pktmbuf_mtod_offset(m, void *, sizeof(struct ether_hdr)); 372 | if (rh_lookup_data(&ctx->ip6_wlst, &ih->src_addr, &ptr) == 0) { 373 | union _entry e; 374 | uint32_t now = US2S(TSC2US(now_tsc)); 375 | e.ptr = ptr; 376 | 377 | if (likely(e.s.ttl > now)) { 378 | return SYNAUTH_OK; 379 | } 380 | } 381 | 382 | return SYNAUTH_IP6_AUTH; 383 | } 384 | -------------------------------------------------------------------------------- /dpdk/firewall/synauth.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef SYNAUTH_H_ 31 | #define SYNAUTH_H_ 32 | 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "rollhash.h" 39 | 40 | #define CIPHER_ALGO (EVP_aes_128_ecb()) 41 | #define CIPHER_KEY_SIZE 16 42 | #define CIPHER_BLOCK_SIZE 16 43 | 44 | struct synauth_ctx { 45 | struct rollhash ip_wlst; 46 | struct rollhash ip6_wlst; 47 | EVP_CIPHER_CTX cipher; 48 | uint8_t key[CIPHER_KEY_SIZE]; 49 | uint64_t key_ttl; 50 | }; 51 | 52 | #define SYNAUTH_OK 0 53 | #define SYNAUTH_IP_AUTH 1 54 | #define SYNAUTH_IP6_AUTH 2 55 | #define SYNAUTH_INVALID 3 56 | #define SYNAUTH_ERROR 4 57 | 58 | int synauth_init(struct synauth_ctx *); 59 | int synauth_vrfy_ip(struct synauth_ctx *, struct rte_mbuf *); 60 | int synauth_vrfy_ip6(struct synauth_ctx *, struct rte_mbuf *); 61 | int synauth_auth_ip(struct synauth_ctx *, struct rte_mbuf *); 62 | int synauth_auth_ip6(struct synauth_ctx *, struct rte_mbuf *); 63 | int synauth_test_ip(struct synauth_ctx *, struct rte_mbuf *); 64 | int synauth_test_ip6(struct synauth_ctx *, struct rte_mbuf *); 65 | 66 | #endif /* SYNAUTH_H_ */ 67 | -------------------------------------------------------------------------------- /dpdk/firewall/tap.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | /* 36 | * Create a tap network interface, or use existing one with same name. 37 | * If name[0]='\0' then a name is automatically assigned and returned in name. 38 | */ 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #include 57 | 58 | #include "main.h" 59 | #include "packet.h" 60 | #include "runtime.h" 61 | #include "forward.h" 62 | 63 | int 64 | tap_create(const char *name, struct nic_cfg *nic) 65 | { 66 | struct ifreq ifr; 67 | int fd, ret, sock, flags; 68 | 69 | sock = -1; 70 | 71 | if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { 72 | ret = fd; 73 | goto done; 74 | } 75 | flags = fcntl(fd, F_GETFL); 76 | fcntl(fd, F_SETFL, flags | O_NONBLOCK); 77 | 78 | memset(&ifr, 0, sizeof(ifr)); 79 | 80 | /* TAP device without packet information */ 81 | flags = IFF_TAP | IFF_NO_PI; 82 | ifr.ifr_flags = flags; 83 | 84 | /* Set the interface name */ 85 | if (name && *name) { 86 | strlcpy(ifr.ifr_name, name, IFNAMSIZ); 87 | } 88 | if ((ret = ioctl(fd, TUNSETIFF, &ifr)) < 0) { 89 | goto done; 90 | } 91 | /* Set the mac address of the tap interface */ 92 | ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; 93 | ether_addr_copy(&nic->hwaddr, 94 | (struct ether_addr *)&ifr.ifr_hwaddr.sa_data); 95 | if ((ret = ioctl(fd, SIOCSIFHWADDR, &ifr) < 0)) { 96 | goto done; 97 | } 98 | /* Make room for the vlan tag */ 99 | if ((ret = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { 100 | goto done; 101 | } 102 | sock = ret; 103 | 104 | ifr.ifr_mtu = 1504; 105 | if ((ret = ioctl(sock, SIOCSIFMTU, &ifr)) < 0) { 106 | goto done; 107 | } 108 | /* Bring the interface up */ 109 | ifr.ifr_flags = flags | IFF_UP; 110 | if ((ret = ioctl(sock, SIOCSIFFLAGS, &ifr)) < 0) { 111 | goto done; 112 | } 113 | done: 114 | if (sock >= 0) { 115 | close(sock); 116 | } 117 | if (ret < 0 && fd >= 0) { 118 | close(fd); 119 | fd = -1; 120 | } 121 | return fd; 122 | } 123 | 124 | uint32_t 125 | tap_fwd_pkts_to_kernel(struct worker_lc_cfg *lp, uint32_t burst) 126 | { 127 | uint32_t ring, n_rings, n_pkts; 128 | 129 | n_pkts = 0; 130 | n_rings = lp->n_irings; 131 | 132 | for (ring = 0; ring < n_rings; ring++) { 133 | struct rte_ring *iring = lp->irings[ring]; 134 | struct rte_mbuf **ibuf = lp->ibuf.array; 135 | unsigned int n_rx, i; 136 | ssize_t ret; 137 | int fd; 138 | 139 | n_rx = rte_ring_sc_dequeue_burst(iring, (void **)ibuf, burst); 140 | if (unlikely(n_rx > burst)) { 141 | RTE_LOG(CRIT, USER1, "TAP: error receiving on ring!\n"); 142 | return n_rx; 143 | } 144 | if (unlikely(n_rx == 0)) { 145 | continue; 146 | } 147 | n_pkts += n_rx; 148 | 149 | #ifdef APP_STATS 150 | lp->irings_pkts[ring] += n_rx; 151 | #endif 152 | 153 | for (i = 0; i < n_rx; i++) { 154 | struct rte_mbuf *m = ibuf[i]; 155 | uint8_t *data; 156 | uint16_t dlen; 157 | 158 | fd = lp->tap.port_to_tap[m->port]; 159 | 160 | /* Try to update the ARP table */ 161 | if (arp_chk_gw_pkt(m, now_tsc)) { 162 | cfg.gws_ts = now_tsc; 163 | } 164 | /* 165 | * The pkt_tag_vlan may change the packet by adding a 166 | * vlan header 167 | */ 168 | data = rte_pktmbuf_mtod(m, uint8_t *); 169 | dlen = pkt_add_vlan_hdr(m); 170 | 171 | /* TODO: retry on EGAIN/EINTR */ 172 | ret = write(fd, data, dlen); 173 | 174 | rte_pktmbuf_free(m); 175 | 176 | if (ret == -1 && errno != EAGAIN && errno != EINTR) { 177 | RTE_LOG(CRIT, USER1, 178 | "Got unexpected error while writing to the " 179 | "tap interface: %u\n", errno); 180 | } 181 | } 182 | } 183 | 184 | return n_pkts; 185 | } 186 | 187 | uint32_t 188 | tap_fwd_pkts_to_nic(struct worker_lc_cfg *lp, uint32_t burst) 189 | { 190 | struct rte_mempool *pool; 191 | uint32_t tap, n_pkts; 192 | 193 | n_pkts = 0; 194 | pool = cfg.pools[rte_socket_id()]; 195 | 196 | for (tap = 0; tap < lp->tap.n_taps; tap++) { 197 | struct rte_mbuf *m; 198 | int ret, fd; 199 | uint32_t pkt, port; 200 | 201 | fd = lp->tap.taps[tap]; 202 | port = lp->tap.tap_to_port[tap]; 203 | 204 | for (pkt = 0; pkt < burst; pkt++) { 205 | m = rte_pktmbuf_alloc(pool); 206 | if (m == NULL) { 207 | RTE_LOG(DEBUG, USER1, "Cannot allocate mbuf.\n"); 208 | continue; 209 | } 210 | ret = read(fd, rte_pktmbuf_mtod(m, void *), MBUF_SIZE); 211 | if (unlikely(ret == -1)) { 212 | if (errno != EAGAIN && errno != EINTR) { 213 | RTE_LOG(ERR, USER1, 214 | "TAP read error: %u\n", errno); 215 | break; 216 | } 217 | rte_pktmbuf_free(m); 218 | break; 219 | } 220 | m->nb_segs = 1; 221 | m->next = NULL; 222 | m->pkt_len = (uint16_t)ret; 223 | m->data_len = (uint16_t)ret; 224 | 225 | m->port = port; 226 | m->udata64 |= PKT_META_ROUTED | PKT_META_VLAN_TAG; 227 | 228 | ret = rte_ring_sp_enqueue_burst( 229 | lp->orings[port], (void **)&m, 1); 230 | if (unlikely(ret < 1)) { 231 | rte_pktmbuf_free(m); 232 | } 233 | n_pkts++; 234 | } 235 | } 236 | 237 | return n_pkts; 238 | } 239 | -------------------------------------------------------------------------------- /dpdk/firewall/util.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #include 31 | 32 | #include "main.h" 33 | #include "util.h" 34 | #include "packet.h" 35 | #include "runtime.h" 36 | 37 | void 38 | util_free_mbufs_burst(struct rte_mbuf **pkts, unsigned count) 39 | { 40 | unsigned i; 41 | 42 | for (i = 0; i < count; i++) { 43 | rte_pktmbuf_free(pkts[i]); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /dpdk/firewall/util.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright (c) 2015, SAPO. All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in 14 | * the documentation and/or other materials provided with the 15 | * distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #ifndef UTIL_H_ 31 | #define UTIL_H_ 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #include "strutil.h" 43 | 44 | #define US2TSC(x) (tsc_per_us * (x)) 45 | #define TSC2US(x) ((x) / tsc_per_us) 46 | 47 | #define US2S(x) (x / US_PER_S) 48 | 49 | #define container_of(ptr, type, member) ({ \ 50 | const typeof(((type *)0)->member) *__mptr = (ptr); \ 51 | (type *)((char *)__mptr - offsetof(type, member));}) 52 | 53 | void util_free_mbufs_burst(struct rte_mbuf **, unsigned); 54 | 55 | static inline int 56 | is_equal128(__m128i a, __m128i b) 57 | { 58 | __m128i zero = _mm_setzero_si128(); 59 | __m128i c = _mm_xor_si128(a, b); 60 | return _mm_testc_si128(zero, c); 61 | } 62 | 63 | static inline int 64 | is_power_of_two(uint32_t a) 65 | { 66 | return (a != 0) && ((a & (a - 1)) == 0); 67 | } 68 | 69 | static inline void 70 | make_ts(char *out, size_t outsiz) 71 | { 72 | char buf[2048]; 73 | struct timeval tv; 74 | struct tm *tm; 75 | 76 | gettimeofday(&tv, NULL); 77 | if ((tm = localtime(&tv.tv_sec)) != NULL) { 78 | strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.", tm); 79 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), 80 | "%06ld", tv.tv_usec); 81 | if (out != NULL) { 82 | snprintf(out, outsiz, "%s", buf); 83 | } 84 | } 85 | } 86 | 87 | #define LOG(l, t, ...) \ 88 | do { \ 89 | uint32_t len; \ 90 | char head[128], buf[2048]; \ 91 | make_ts(head, sizeof(head)); \ 92 | snprintf(buf, sizeof(buf), "%s [%u] ", \ 93 | head, rte_lcore_id()); \ 94 | len = strlen(buf); \ 95 | snprintf(buf + len, sizeof(buf) - len, __VA_ARGS__); \ 96 | rte_log( \ 97 | RTE_LOG_ ## l, RTE_LOGTYPE_ ## t, # t ": %s", buf); \ 98 | } while (0) 99 | 100 | static inline void 101 | util_flush_sp_ring_buffer(struct rte_ring *ring, struct mbuf_array *buffer) 102 | { 103 | unsigned n_tx; 104 | 105 | n_tx = rte_ring_sp_enqueue_burst(ring, (void **)buffer->array, 106 | buffer->n_mbufs); 107 | if (unlikely(n_tx < buffer->n_mbufs)) { 108 | util_free_mbufs_burst(&buffer->array[n_tx], 109 | buffer->n_mbufs - n_tx); 110 | } 111 | buffer->n_mbufs = 0; 112 | } 113 | 114 | static inline void 115 | util_flush_mp_ring_buffer(struct rte_ring *ring, struct mbuf_array *buffer) 116 | { 117 | unsigned n_tx; 118 | 119 | n_tx = rte_ring_mp_enqueue_burst(ring, (void **)buffer->array, 120 | buffer->n_mbufs); 121 | if (unlikely(n_tx < buffer->n_mbufs)) { 122 | util_free_mbufs_burst(&buffer->array[n_tx], 123 | buffer->n_mbufs - n_tx); 124 | } 125 | buffer->n_mbufs = 0; 126 | } 127 | 128 | #endif /* UTIL_H_ */ 129 | -------------------------------------------------------------------------------- /dpdk/firewall/worker.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #include 36 | 37 | #include "main.h" 38 | #include "util.h" 39 | #include "runtime.h" 40 | 41 | void 42 | wrk_lcore_main_loop(__attribute__((unused)) void *arg) 43 | { 44 | struct worker_lc_cfg *lp; 45 | void (*wrk_loop) (struct worker_lc_cfg *); 46 | uint32_t lcore; 47 | 48 | rcu_register_thread(); 49 | 50 | lcore = rte_lcore_id(); 51 | lp = &cfg.lcores[lcore].worker; 52 | 53 | switch (lp->type) { 54 | case WORKER_TYPE_FW: 55 | wrk_loop = lp->ol == WORKER_OL_PROV ? 56 | fw_lcore_main_loop_tsc : fw_lcore_main_loop_cnt; 57 | break; 58 | case WORKER_TYPE_CTRL_KNI: 59 | /* Fall through */ 60 | case WORKER_TYPE_CTRL_TAP: 61 | wrk_loop = ctrl_lcore_main_loop; 62 | break; 63 | default: 64 | rte_panic("Unknown worker type: %u.\n", lp->type); 65 | } 66 | 67 | wrk_loop(lp); 68 | } 69 | -------------------------------------------------------------------------------- /dpdk/firewall/zone.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * BSD LICENSE 3 | * 4 | * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 | * Copyright(c) 2015 SAPO. All rights reserved. 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions 10 | * are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright 13 | * notice, this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in 16 | * the documentation and/or other materials provided with the 17 | * distribution. 18 | * * Neither the name of Intel Corporation nor the names of its 19 | * contributors may be used to endorse or promote products derived 20 | * from this software without specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef ZONE_H_ 36 | #define ZONE_H_ 37 | 38 | #include 39 | 40 | #include "main.h" 41 | 42 | #define MAX_ACL_STR_SIZE 256 43 | 44 | struct zone_cfg { 45 | char name[MAX_ZONE_LEN]; 46 | struct rte_acl_ctx *ip_acl[MAX_SOCKETS]; 47 | struct rte_acl_ctx *ip6_acl[MAX_SOCKETS]; 48 | struct rte_hash *ip_nat_k[MAX_SOCKETS]; 49 | uint32_t *ip_nat_v[MAX_SOCKETS]; 50 | char rules[MAX_ACL_COUNTERS][MAX_ACL_STR_SIZE]; 51 | uint8_t n_rules; 52 | uint32_t version; 53 | uint8_t reverse; 54 | uint8_t id; 55 | }; 56 | 57 | #endif /* ZONE_H_ */ 58 | -------------------------------------------------------------------------------- /tests/raw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #define FILTERSIZE 1024 15 | #define CAPSIZE 1500 16 | 17 | struct p_tcphdr { 18 | struct in_addr srcip; 19 | struct in_addr dstip; 20 | uint8_t zeroes; 21 | uint8_t protocol; 22 | uint16_t len; 23 | } __attribute__((__packed__)); 24 | 25 | uint16_t 26 | in_cksum(void *addr, size_t size, uint16_t init) 27 | { 28 | uint16_t *buffer; 29 | uint32_t cksum; 30 | 31 | buffer = addr; 32 | cksum = init; 33 | 34 | while (size > 1) { 35 | cksum += *buffer++; 36 | size -= sizeof(uint16_t); 37 | } 38 | 39 | if (size) 40 | cksum += *(uint8_t *)buffer; 41 | 42 | while (cksum >> 16) 43 | cksum = (cksum >> 16) + (cksum & 0xffff); 44 | 45 | return (uint16_t)(~cksum); 46 | } 47 | 48 | static void 49 | hexdump(const void *data, size_t size) { 50 | char ascii[17]; 51 | size_t i, j; 52 | ascii[16] = '\0'; 53 | 54 | for (i = 0; i < size; i++) { 55 | printf("%02X ", ((uint8_t*) data)[i]); 56 | if (((uint8_t *) data)[i] >= ' '&& 57 | ((uint8_t *) data)[i] <= '~') { 58 | ascii[i % 16] = ((uint8_t*) data)[i]; 59 | } else { 60 | ascii[i % 16] = '.'; 61 | } 62 | if ((i + 1) % 8 == 0 || i + 1 == size) { 63 | printf(" "); 64 | if ((i + 1) % 16 == 0) { 65 | printf("| %s \n", ascii); 66 | } else if (i + 1 == size) { 67 | ascii[(i + 1) % 16] = '\0'; 68 | if ((i + 1) % 16 <= 8) { 69 | printf(" "); 70 | } 71 | for (j = (i + 1) % 16; j < 16; ++j) { 72 | printf(" "); 73 | } 74 | printf("| %s \n", ascii); 75 | } 76 | } 77 | } 78 | } 79 | 80 | static size_t 81 | create_syn_challenge(uint8_t *data, size_t len) 82 | { 83 | struct ether_addr ea; 84 | struct in_addr ina; 85 | struct p_tcphdr pth; 86 | struct ether_header *eh; 87 | struct ip *ih; 88 | struct tcphdr *th; 89 | size_t iplen; 90 | uint16_t port, csum; 91 | static int cnt = 0; 92 | uint8_t rand[8]; 93 | int fd; 94 | 95 | eh = (struct ether_header *)data; 96 | ih = (struct ip *)(data + sizeof(struct ether_header)); 97 | th = (struct tcphdr *) 98 | (data + sizeof(struct ether_header) + sizeof(struct ip)); 99 | 100 | /* Ethernet */ 101 | memcpy(&ea, &eh->ether_shost, sizeof(struct ether_addr)); 102 | memcpy(&eh->ether_shost, &eh->ether_dhost, sizeof(struct ether_addr)); 103 | memcpy(&eh->ether_dhost, &ea, sizeof(struct ether_addr)); 104 | 105 | /* IP */ 106 | ina = ih->ip_src; 107 | ih->ip_src = ih->ip_dst; 108 | ih->ip_dst = ina; 109 | ih->ip_sum = 0; 110 | ih->ip_sum = in_cksum(ih, ih->ip_hl * 4, 0); 111 | 112 | /* TCP */ 113 | port = th->th_sport; 114 | th->th_sport = th->th_dport; 115 | th->th_dport = port; 116 | th->th_sum = 0; 117 | 118 | /* XXX: check open() and read() return values */ 119 | fd = open("/dev/urandom", O_RDONLY); 120 | read(fd, &rand, sizeof(rand)); 121 | close(fd); 122 | 123 | /* ACK an out-of-sequence initial sequence number */ 124 | th->th_flags |= TH_ACK; 125 | if (cnt < 2) { 126 | th->th_ack = *(uint32_t *)rand; 127 | fprintf(stderr, 128 | "[+] Sending out-of-sequence SYN+ACK reply: " 129 | "%" PRIu32 " (should be: %" PRIu32 ")\n", 130 | ntohl(th->th_ack), ntohl(th->th_seq) + 1); 131 | cnt++; 132 | } else { 133 | th->th_ack = htonl(ntohl(th->th_seq) + 1); 134 | fprintf(stderr, 135 | "[+] Sending correct SYN+ACK reply: %" PRIu32 "\n", 136 | ntohl(th->th_ack)); 137 | cnt = 0; 138 | } 139 | th->th_seq = *(uint32_t *) rand + 4; 140 | 141 | /* TCP checksum */ 142 | iplen = ntohs(ih->ip_len); 143 | iplen -= ih->ip_hl * 4; 144 | 145 | pth.srcip = ih->ip_src; 146 | pth.dstip = ih->ip_dst; 147 | pth.zeroes = 0; 148 | pth.protocol = IPPROTO_TCP; 149 | pth.len = htons(iplen); 150 | 151 | csum = in_cksum(&pth, sizeof(struct p_tcphdr), 0); 152 | th->th_sum = in_cksum(th, iplen, ~csum); 153 | 154 | return len; 155 | } 156 | 157 | static void 158 | handler(uint8_t *addr, const struct pcap_pkthdr *hdr, const uint8_t *data) 159 | { 160 | uint8_t buffer[CAPSIZE]; 161 | pcap_t *h; 162 | struct ip *ih; 163 | struct tcphdr *th; 164 | 165 | /* 166 | printf("Got this:\n"); 167 | hexdump(data, hdr->len); 168 | */ 169 | 170 | /* XXX: headers and size sanity checks */ 171 | 172 | h = (pcap_t *)addr; 173 | ih = (struct ip *)(data + sizeof(struct ether_header)); 174 | th = (struct tcphdr *) 175 | (data + sizeof(struct ether_header) + sizeof(struct ip)); 176 | 177 | if (ih->ip_p != IPPROTO_TCP) { 178 | fprintf(stderr, "[-] Ignoring non-TCP packet...\n"); 179 | return; 180 | } 181 | 182 | if (th->th_flags & TH_SYN) { 183 | size_t len; 184 | 185 | if (th->th_flags & TH_ACK) { 186 | fprintf(stderr, "[-] Ignoring SYN+ACK reply...\n"); 187 | } 188 | 189 | len = hdr->len; 190 | fprintf(stderr, "[+] Received SYN packet...\n"); 191 | memcpy(buffer, data, hdr->len); 192 | if ((len = create_syn_challenge(buffer, len)) == 0) { 193 | fprintf(stderr, "[!] Could not build packet.\n"); 194 | return; 195 | } 196 | 197 | if (pcap_inject(h, buffer, len) == -1) { 198 | fprintf(stderr, 199 | "[!] Could not send packet: %s\n", pcap_geterr(h)); 200 | } 201 | } else if ((th->th_flags & TH_ACK) && 202 | !(th->th_flags & (TH_PUSH|TH_FIN|TH_RST))) { 203 | fprintf(stderr, "[+] Connection established.\n"); 204 | } else if (th->th_flags & TH_RST) { 205 | fprintf(stderr, "[-] Connection reset by remote host. " 206 | "Sequence number: %" PRIu32 ".\n", ntohl(th->th_seq)); 207 | } 208 | } 209 | 210 | int 211 | main(int argc, char *argv[]) 212 | { 213 | char filter[FILTERSIZE]; 214 | char errbuf[PCAP_ERRBUF_SIZE]; 215 | struct bpf_program bpf; 216 | char *dev, *port_str; 217 | pcap_t *h; 218 | uint32_t mask, net; 219 | uint16_t port; 220 | 221 | if (argc < 3) { 222 | fprintf(stderr, "usage: %s \n", argv[0]); 223 | return -1; 224 | } 225 | 226 | dev = argv[1]; 227 | port_str = argv[2]; 228 | 229 | if (sscanf(port_str, "%" SCNu16, &port) != 1) { 230 | fprintf(stderr, "Invalid port number: %s\n", port_str); 231 | return -1; 232 | } 233 | 234 | if (pcap_lookupnet(dev, &net, &mask, errbuf) != 0) { 235 | fprintf(stderr, 236 | "Could not get netmask for device %s\n", dev); 237 | net = 0; 238 | mask = 0; 239 | } 240 | 241 | if ((h = pcap_open_live(dev, CAPSIZE, 0, 1000, errbuf)) == NULL) { 242 | fprintf(stderr, 243 | "Error opening device %s: %s\n", dev, errbuf); 244 | return -1; 245 | } 246 | 247 | if (pcap_datalink(h) != DLT_EN10MB) { 248 | fprintf(stderr, 249 | "%s does not support ethernet headers\n", dev); 250 | return -1; 251 | } 252 | 253 | snprintf(filter, sizeof(filter), "tcp port %" PRIu16, port); 254 | if (pcap_compile(h, &bpf, filter, 0, net) != 0) { 255 | fprintf(stderr, 256 | "Could not parse filter %s: %s\n", filter, pcap_geterr(h)); 257 | return -1; 258 | } 259 | 260 | if (pcap_setfilter(h, &bpf) != 0) { 261 | fprintf(stderr, 262 | "Could not install filter %s: %s\n", filter, pcap_geterr(h)); 263 | return -1; 264 | } 265 | 266 | pcap_loop(h, -1, handler, (uint8_t *)h); 267 | 268 | pcap_freecode(&bpf); 269 | pcap_close(h); 270 | 271 | return 0; 272 | } 273 | --------------------------------------------------------------------------------