From owner-svn-src-projects@FreeBSD.ORG Thu Aug 14 22:01:29 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 1E0F2C16; Thu, 14 Aug 2014 22:01:29 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3BBF62B3F; Thu, 14 Aug 2014 20:17:24 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s7EKHObw083985; Thu, 14 Aug 2014 20:17:24 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s7EKHN5W083982; Thu, 14 Aug 2014 20:17:23 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <201408142017.s7EKHN5W083982@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Thu, 14 Aug 2014 20:17:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r270001 - projects/ipfw/sys/netpfil/ipfw X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Aug 2014 22:01:29 -0000 Author: melifaro Date: Thu Aug 14 20:17:23 2014 New Revision: 270001 URL: http://svnweb.freebsd.org/changeset/base/270001 Log: * Add cidr:kfib algo type just for fun. It binds kernel fib of given number to a table. Example: # ipfw table fib2 create algo "cidr:kfib fib=2" # ipfw table fib2 info +++ table(fib2), set(0) +++ kindex: 2, type: cidr, locked valtype: number, references: 0 algorithm: cidr:kfib fib=2 items: 11, size: 288 # ipfw table fib2 list +++ table(fib2), set(0) +++ 10.0.0.0/24 0 127.0.0.1/32 0 ::/96 0 ::1/128 0 ::ffff:0.0.0.0/96 0 2a02:978:2::/112 0 fe80::/10 0 fe80:1::/64 0 fe80:2::/64 0 fe80:3::/64 0 ff02::/16 0 # ipfw table fib2 lookup 10.0.0.5 10.0.0.0/24 0 # ipfw table fib2 lookup 2a02:978:2::11 2a02:978:2::/112 0 # ipfw table fib2 detail +++ table(fib2), set(0) +++ kindex: 2, type: cidr, locked valtype: number, references: 0 algorithm: cidr:kfib fib=2 items: 11, size: 288 IPv4 algorithm radix info items: 0 itemsize: 200 IPv6 algorithm radix info items: 0 itemsize: 200 Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Aug 14 19:15:20 2014 (r270000) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.c Thu Aug 14 20:17:23 2014 (r270001) @@ -1885,6 +1885,60 @@ ipfw_mark_table_kidx(struct ip_fw_chain return (count); } +struct dump_args { + struct table_info *ti; + struct table_config *tc; + struct sockopt_data *sd; + uint32_t cnt; + uint16_t uidx; + int error; + ipfw_table_entry *ent; + uint32_t size; + ipfw_obj_tentry tent; +}; + +static int +count_ext_entries(void *e, void *arg) +{ + struct dump_args *da; + + da = (struct dump_args *)arg; + da->cnt++; + + return (0); +} + +/* + * Gets number of items from table either using + * internal counter or calling algo callback for + * externally-managed tables. + * + * Returns number of records. + */ +static uint32_t +table_get_count(struct ip_fw_chain *ch, struct table_config *tc) +{ + struct table_info *ti; + struct table_algo *ta; + struct dump_args da; + + ti = KIDX_TO_TI(ch, tc->no.kidx); + ta = tc->ta; + + /* Use internal counter for self-managed tables */ + if ((ta->flags & TA_FLAG_READONLY) == 0) + return (tc->count); + + /* Use callback to quickly get number of items */ + if ((ta->flags & TA_FLAG_EXTCOUNTER) != 0) + return (ta->get_count(tc->astate, ti)); + + /* Count number of iterms ourselves */ + memset(&da, 0, sizeof(da)); + ta->foreach(tc->astate, ti, count_ext_entries, &da); + + return (da.cnt); +} /* * Exports table @tc info into standard ipfw_xtable_info format. @@ -1903,7 +1957,7 @@ export_table_info(struct ip_fw_chain *ch i->set = tc->no.set; i->kidx = tc->no.kidx; i->refcnt = tc->no.refcnt; - i->count = tc->count; + i->count = table_get_count(ch, tc); i->limit = tc->limit; i->flags |= (tc->locked != 0) ? IPFW_TGFLAGS_LOCKED : 0; i->size = tc->count * sizeof(ipfw_obj_tentry); @@ -1982,18 +2036,6 @@ export_tables(struct ip_fw_chain *ch, ip return (0); } -struct dump_args { - struct table_info *ti; - struct table_config *tc; - struct sockopt_data *sd; - uint32_t cnt; - uint16_t uidx; - int error; - ipfw_table_entry *ent; - uint32_t size; - ipfw_obj_tentry tent; -}; - int ipfw_dump_table(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd) @@ -2092,7 +2134,7 @@ ipfw_dump_table_v0(struct ip_fw_chain *c struct table_config *tc; struct table_algo *ta; struct dump_args da; - size_t sz; + size_t sz, count; xtbl = (ipfw_xtable *)ipfw_get_sopt_header(sd, sizeof(ipfw_xtable)); if (xtbl == NULL) @@ -2106,9 +2148,10 @@ ipfw_dump_table_v0(struct ip_fw_chain *c IPFW_UH_RUNLOCK(ch); return (0); } - sz = tc->count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); + count = table_get_count(ch, tc); + sz = count * sizeof(ipfw_table_xentry) + sizeof(ipfw_xtable); - xtbl->cnt = tc->count; + xtbl->cnt = count; xtbl->size = sz; xtbl->type = tc->no.type; xtbl->tbl = ti.uidx; @@ -2149,7 +2192,7 @@ ipfw_count_table(struct ip_fw_chain *ch, if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) return (ESRCH); - *cnt = tc->count; + *cnt = table_get_count(ch, tc); return (0); } @@ -2160,13 +2203,16 @@ int ipfw_count_xtable(struct ip_fw_chain *ch, struct tid_info *ti, uint32_t *cnt) { struct table_config *tc; + uint32_t count; if ((tc = find_table(CHAIN_TO_NI(ch), ti)) == NULL) { *cnt = 0; return (0); /* 'table all list' requires success */ } - *cnt = tc->count * sizeof(ipfw_table_xentry); - if (tc->count > 0) + + count = table_get_count(ch, tc); + *cnt = count * sizeof(ipfw_table_xentry); + if (count > 0) *cnt += sizeof(ipfw_xtable); return (0); } Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Thu Aug 14 19:15:20 2014 (r270000) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table.h Thu Aug 14 20:17:23 2014 (r270001) @@ -105,6 +105,7 @@ typedef int ta_find_tentry(void *ta_stat ipfw_obj_tentry *tent); typedef void ta_dump_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo); +typedef uint32_t ta_get_count(void *ta_state, struct table_info *ti); struct table_algo { char name[16]; @@ -131,9 +132,11 @@ struct table_algo { ta_dump_tentry *dump_tentry; ta_print_config *print_config; ta_dump_tinfo *dump_tinfo; + ta_get_count *get_count; }; #define TA_FLAG_DEFAULT 0x01 /* Algo is default for given type */ #define TA_FLAG_READONLY 0x02 /* Algo does not support modifications*/ +#define TA_FLAG_EXTCOUNTER 0x04 /* Algo has external counter available*/ int ipfw_add_table_algo(struct ip_fw_chain *ch, struct table_algo *ta, size_t size, int *idx); Modified: projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c ============================================================================== --- projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Thu Aug 14 19:15:20 2014 (r270000) +++ projects/ipfw/sys/netpfil/ipfw/ip_fw_table_algo.c Thu Aug 14 20:17:23 2014 (r270001) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD: projects/ipfw/sys/ne #include #include /* ip_fw.h requires IFNAMSIZ */ #include +#include #include #include /* struct ipfw_rule_ref */ @@ -3519,6 +3520,263 @@ struct table_algo flow_hash = { .flush_mod = ta_flush_mod_fhash, }; +/* + * Kernel fibs bindings. + * + * Implementation: + * + * Runtime part: + * - fully relies on route API + * - fib number is stored in ti->data + * + */ + +static struct rtentry * +lookup_kfib(void *key, int keylen, int fib) +{ + struct sockaddr *s; + + if (keylen == 4) { + struct sockaddr_in sin; + bzero(&sin, sizeof(sin)); + sin.sin_len = sizeof(struct sockaddr_in); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = *(in_addr_t *)key; + s = (struct sockaddr *)&sin; + } else { + struct sockaddr_in6 sin6; + bzero(&sin6, sizeof(sin6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = *(struct in6_addr *)key; + s = (struct sockaddr *)&sin6; + } + + return (rtalloc1_fib(s, 0, 0, fib)); +} + +static int +ta_lookup_kfib(struct table_info *ti, void *key, uint32_t keylen, + uint32_t *val) +{ + struct rtentry *rte; + + if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) + return (0); + + *val = 0; + RTFREE_LOCKED(rte); + + return (1); +} + +/* Parse 'fib=%d' */ +static int +kfib_parse_opts(int *pfib, char *data) +{ + char *pdel, *pend, *s; + int fibnum; + + if (data == NULL) + return (0); + if ((pdel = strchr(data, ' ')) == NULL) + return (0); + while (*pdel == ' ') + pdel++; + if (strncmp(pdel, "fib=", 4) != 0) + return (EINVAL); + if ((s = strchr(pdel, ' ')) != NULL) + *s++ = '\0'; + + pdel += 4; + /* Need \d+ */ + fibnum = strtol(pdel, &pend, 10); + if (*pend != '\0') + return (EINVAL); + + *pfib = fibnum; + + return (0); +} + +static void +ta_print_kfib_config(void *ta_state, struct table_info *ti, char *buf, + size_t bufsize) +{ + + if (ti->data != 0) + snprintf(buf, bufsize, "%s fib=%lu", "cidr:kfib", ti->data); + else + snprintf(buf, bufsize, "%s", "cidr:kfib"); +} + +static int +ta_init_kfib(struct ip_fw_chain *ch, void **ta_state, struct table_info *ti, + char *data, uint8_t tflags) +{ + int error, fibnum; + + fibnum = 0; + if ((error = kfib_parse_opts(&fibnum, data)) != 0) + return (error); + + if (fibnum >= rt_numfibs) + return (E2BIG); + + ti->data = fibnum; + ti->lookup = ta_lookup_kfib; + + return (0); +} + +/* + * Destroys table @ti + */ +static void +ta_destroy_kfib(void *ta_state, struct table_info *ti) +{ + +} + +/* + * Provide algo-specific table info + */ +static void +ta_dump_kfib_tinfo(void *ta_state, struct table_info *ti, ipfw_ta_tinfo *tinfo) +{ + + tinfo->flags = IPFW_TATFLAGS_AFDATA; + tinfo->taclass4 = IPFW_TACLASS_RADIX; + tinfo->count4 = 0; + tinfo->itemsize4 = sizeof(struct rtentry); + tinfo->taclass6 = IPFW_TACLASS_RADIX; + tinfo->count6 = 0; + tinfo->itemsize6 = sizeof(struct rtentry); +} + +static int +contigmask(uint8_t *p, int len) +{ + int i, n; + + for (i = 0; i < len ; i++) + if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */ + break; + for (n= i + 1; n < len; n++) + if ( (p[n/8] & (1 << (7 - (n % 8)))) != 0) + return (-1); /* mask not contiguous */ + return (i); +} + + +static int +ta_dump_kfib_tentry(void *ta_state, struct table_info *ti, void *e, + ipfw_obj_tentry *tent) +{ + struct rtentry *rte; + struct sockaddr_in *addr, *mask; + struct sockaddr_in6 *addr6, *mask6; + int len; + + rte = (struct rtentry *)e; + addr = (struct sockaddr_in *)rt_key(rte); + mask = (struct sockaddr_in *)rt_mask(rte); + len = 0; + + /* Guess IPv4/IPv6 radix by sockaddr family */ + if (addr->sin_family == AF_INET) { + tent->k.addr.s_addr = addr->sin_addr.s_addr; + len = 32; + if (mask != NULL) + len = contigmask((uint8_t *)&mask->sin_addr, 32); + if (len == -1) + len = 0; + tent->masklen = len; + tent->subtype = AF_INET; + tent->value = 0; /* Do we need to put GW here? */ +#ifdef INET6 + } else if (addr->sin_family == AF_INET6) { + addr6 = (struct sockaddr_in6 *)addr; + mask6 = (struct sockaddr_in6 *)mask; + memcpy(&tent->k, &addr6->sin6_addr, sizeof(struct in6_addr)); + len = 128; + if (mask6 != NULL) + len = contigmask((uint8_t *)&mask6->sin6_addr, 128); + if (len == -1) + len = 0; + tent->masklen = len; + tent->subtype = AF_INET6; + tent->value = 0; +#endif + } + + return (0); +} + +static int +ta_find_kfib_tentry(void *ta_state, struct table_info *ti, + ipfw_obj_tentry *tent) +{ + struct rtentry *rte; + void *key; + int keylen; + + if (tent->subtype == AF_INET) { + key = &tent->k.addr; + keylen = sizeof(struct in_addr); + } else { + key = &tent->k.addr6; + keylen = sizeof(struct in6_addr); + } + + if ((rte = lookup_kfib(key, keylen, ti->data)) == NULL) + return (0); + + if (rte != NULL) { + ta_dump_kfib_tentry(ta_state, ti, rte, tent); + RTFREE_LOCKED(rte); + return (0); + } + + return (ENOENT); +} + +static void +ta_foreach_kfib(void *ta_state, struct table_info *ti, ta_foreach_f *f, + void *arg) +{ + struct radix_node_head *rnh; + int error; + + rnh = rt_tables_get_rnh(ti->data, AF_INET); + if (rnh != NULL) { + RADIX_NODE_HEAD_RLOCK(rnh); + error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); + RADIX_NODE_HEAD_RUNLOCK(rnh); + } + + rnh = rt_tables_get_rnh(ti->data, AF_INET6); + if (rnh != NULL) { + RADIX_NODE_HEAD_RLOCK(rnh); + error = rnh->rnh_walktree(rnh, (walktree_f_t *)f, arg); + RADIX_NODE_HEAD_RUNLOCK(rnh); + } +} + +struct table_algo cidr_kfib = { + .name = "cidr:kfib", + .type = IPFW_TABLE_CIDR, + .flags = TA_FLAG_READONLY, + .ta_buf_size = 0, + .init = ta_init_kfib, + .destroy = ta_destroy_kfib, + .foreach = ta_foreach_kfib, + .dump_tentry = ta_dump_kfib_tentry, + .find_tentry = ta_find_kfib_tentry, + .dump_tinfo = ta_dump_kfib_tinfo, + .print_config = ta_print_kfib_config, +}; + void ipfw_table_algo_init(struct ip_fw_chain *ch) { @@ -3533,6 +3791,7 @@ ipfw_table_algo_init(struct ip_fw_chain ipfw_add_table_algo(ch, &iface_idx, sz, &iface_idx.idx); ipfw_add_table_algo(ch, &number_array, sz, &number_array.idx); ipfw_add_table_algo(ch, &flow_hash, sz, &flow_hash.idx); + ipfw_add_table_algo(ch, &cidr_kfib, sz, &cidr_kfib.idx); } void @@ -3544,6 +3803,7 @@ ipfw_table_algo_destroy(struct ip_fw_cha ipfw_del_table_algo(ch, iface_idx.idx); ipfw_del_table_algo(ch, number_array.idx); ipfw_del_table_algo(ch, flow_hash.idx); + ipfw_del_table_algo(ch, cidr_kfib.idx); }