diff -Nru pmacct-0.12.1/ChangeLog pmacct-0.12.5/ChangeLog --- pmacct-0.12.1/ChangeLog 2010-04-04 21:03:26.000000000 +0000 +++ pmacct-0.12.5/ChangeLog 2010-12-27 11:53:53.000000000 +0000 @@ -1,6 +1,186 @@ -pmacct (Promiscuous mode IP Accounting package) v0.12.1 +pmacct (Promiscuous mode IP Accounting package) v0.12.5 pmacct is Copyright (C) 2003-2010 by Paolo Lucente +0.12.5 -- 28-12-2010 + + nfacctd: introduced support for NAT L3/L4 field values via xlate_src + and xlate_dst configuration directives. Implementation follows IPFIX + standard for IPv4 and IPv6 (field types 225, 226, 227, 228, 281 and + 282). + + nfacctd: Cisco ASA NetFlow v9 NSEL field types 40001, 40002, 40003, + 40004 and IPFIX/Cisco ASA NetFlow v9 NSEL msecs absolute timestamps + field types 152, 153 and 323 have been added. + + nfacctd: introduced support for 'new' TCP/UDP source/destination ports + (field types 180, 181, 182, 183), as per IPFIX standard, basing on the + L4 protocol value (if any is specified as part of the export; otherwise + assume L4 is not TCP/UDP). + + nfacctd, nfprobe: introduced support for application classification + via NetFlow v9 field type #95 (application ID) and application name + table option. This feature aligns with Cisco NBAR-NetFlow v9 + integration feature. + + nfacctd: introduced support for egress bytes and packet counters (field + types 23, 24) basing on the direction value (if any is specified as + part of the export; otherwise assume ingress as per RFC3954). + + nfprobe: egress IPv4/IPv6 NetFlow v9 templates have been introduced; + compatibility with Cisco (no use of OUT_BYTES, OUT_OUT_PACKETS) taken + into account. + + nfacctd: added support for egress datalink NetFlow v9 fields basing + on direction field. + + nfacctd, sfacctd: aggregate_filter can now filter against TCP flags; + also, [ns]facctd_net directive can now be specified per-plugin. + + BGP daemon: introduced support for IPv6 transport of BGP messaging. + + BGP daemon: BGP peer information is now linked into the status table + for caching purposes. This optimization results in good CPU savings + in bigger deployments. + ! fix, nfacctd, sfacctd: daemons were crashing on OpenBSD platform upon + setting an aggregate_filter configuration directive. Patch is courtesy + of Manuel Pata. + ! fix, xflow_status.c: status entries were not properly linked to the + hash conflict chain resulting in a memory leak. However the maximum + number of table entries set by default was preventing the structure + to grow undefinitely. + ! fix, sql_common.c: increased buffer size available for sql_table_schema + from 1KB to 8KB. Thanks to Michiel Muhlenbaumer his support. + ! fix, bgp_agent_map has been improved to allow mapping of NetFlow/sFlow + agents making use of IPv6 transport to either a) IPv4 transport address + of BGP sessions or b) 32-bit BGP Router IDs. Mapping to IPv6 addresses + is however not (yet) possible. + ! fix, nfprobe: encoding of NetFlow v9 option scope has been improved; + nfprobe source IPv4/IPv6 address, if specified via nfprobe_source_ip + directive, is now being written. + ! fix, util.c: string copies in trim_spaces(), trim_all_spaces() and + strip_quotes() have been rewritten more safely. Patch is courtesy of + Dmitry Koplovich. + ! fix, sfacctd: interface format is now merged back into interface value + fields so to ease keeping track of discards (and discard reasons) and + multicast fanout. + ! fix, MySQL, SQLite3 plugins: sql table version 8 issued to provide + common naming convention when mapping primitives to database fields + among the supported RDBMS base. Thanks to Chris Wilson for his support. + ! fix, pmacct client: numeric variables output converted to unsigned + from signed. + ! fix, nfacctd_net, sfacctd_net: default value changed from null (and + related error message) to 'netflow' for nfacctd_net and 'sflow' for + sfacctd_net. + ! fix, nfacctd, sfacctd: aggregate_filter was not catching L2 primitives + (VLAN, MAC addresses) when performing egress measurements. + +0.12.4 -- 01-10-2010 + + BGP daemon: a new memory model is introduced by which IP prefixes + are being shared among the BGP peers RIBs - leading to consistent + memory savings whenever multiple BGP peers export full tables due + to the almost total overlap of information. Longest match nature + of IP lookups required to raise BGP peer awareness of the lookup + algorithm. Updated INTERNALS document to support estimation of the + memory footprint of the daemon. + + BGP daemon: a new bgp_table_peer_buckets configuration directive + is introduced: per-peer routing information is attached to IP + prefixes and now hashed onto buckets with conflict chains. This + parameter sets the number of buckets of such hash structure; the + value is directly related to the number of expected BGP peers, + should never exceed such amount and is best set to 1/10 of the + expected number of peers. + + nfprobe: support has been added to export direction field (NetFlow + v9 field type #61); its value, 0=ingress 1=egress, is determined + via nfprobe_direction configuration directive. + + nfacctd: introduced support for Cisco ASA bytes counter, NetFlow v9 + field type #85. Thanks to Ralf Reinartz for his support. + + nfacctd: improved flow recognition heuristics for cases in which + IPv4/IPv6/input/output data are combined within the same NetFlow + v9 template. Thanks to Carsten Schoene for his support. + ! fix, BGP daemon: bgp_nexthop_followup was not working correctly if + pointed to a non-existing next-hop. + ! fix, nfv9_template.c: ignoring unsupported NetFlow v9 field types; + improved template logging. Thanks to Ralf Reinartz for his support. + ! fix, print plugin: support for interfaces and network masks has + been added. Numeric variables output converted to unsigned from + signed. + +0.12.3 -- 28-07-2010 + + 'cos' aggregation primitive has been implemented providing support + for 802.1p priority. Collection is supported via sFlow, libpcap and + ULOG; export is supported via sFlow. + + BGP daemon: TCP MD5 signature implemented. New 'bgp_daemon_md5_file' + configuration directive is being added for the purpose of defining + peers and their respective MD5 keys, one per line, in CSV format. + The map is reloadable at runtime: existing MD5 keys are removed via + setsockopt(), new ones are installed as per the newly supplied map. + Sample map added in 'examples/bgp_md5.lst.example'. + + BGP daemon: added support for RFC3107 (SAFI=4 label information) to + enable receipt of labeled IPv4/IPv6 unicast prefixes. + + nfprobe, sfprobe: introduced the concept of traffic direction. As a + result, [ns]fprobe_direction and [ns]fprobe_ifindex configuration + directives have been implemented. + + [ns]fprobe_direction defines traffic direction. It can be statically + defined via 'in' or 'out' keywords; values can also be dynamically + determined through a pre_tag_map (1=input, 2=output) by means of + 'tag' and 'tag2' keywords. + + [ns]fprobe_ifindex either statically associate an interface index + (ifIndex) to a given [ns]fprobe plugin or semi-dynamically via + lookups against a pre_tag_map by means of 'tag' and 'tag2' keywords. + + sfprobe: sfprobe_ifspeed configuration directive is introduced and + aimed at statically associating an interface speed to an sfprobe + plugin. + + sfprobe: Switch Extension Header support added. Enabler for this + development was support for 'cos' and in/out direction. Whereas + VLAN information was already supported as an aggregation primitive. + + sfprobe: added support for Counter Samples for multiple interfaces. + Sampling function has been brought to the plugin so that Counter + Samples can be populated with real bytes/packets traffic levels. + ! nfprobe, sfprobe: send buffer size is now aligned to plugin_pipe_size, + if specified, providing a way to tune buffers in case of sustained + exports. + ! fix, addr.c: pm_ntohll() and pm_htonll() routines rewritten. These + are aimed at changing byte ordering of 64-bit variables. + ! fix, BGP daemon: support for IPv6 global address/link-local address + next-hops as part of MP_REACH_NLRI parsing. + ! fix, cfg_handlers.c: bgp_daemon and bgp_daemon_msglog parsing was + not correct, ie. enabled if specified as 'false'. Thanks to Brent + Van Dussen for reporting the issue. + ! fix, bgp.c: found a CPU hog issue caused by missing cleanup of the + select() descriptors vector. + ! fix, pmacct.c: in_iface/out_iface did erroneously fall inside a + section protected by the "--disable-l2" switch. Thanks to Brent + Van Dussen for reporting the issue. + +0.12.2 -- 27-05-2010 + + A new 'tee' plugin is introduced bringing both NetFlow and sFlow + replication capabilities to pmacct. It supports transparent mode + (tee_transparent), coarse-grained filtering capabilities via the + Pre-Tagging infrastructure. Quickstart guide is included as part + of the EXAMPLES file (chapter XII). + + nfprobe, sfprobe: introduced support for export of the BGP next-hop + information. Source data selection for BGP next-hop is being linked + to [pmacctd_as|uacctd_as] configuration directive. Hence it must be + set to 'bgp' in order for this feature to work. + + nfprobe, sfprobe, BGP daemon: new set of features (nfprobe_ipprec, + sfprobe_ipprec, bgp_daemon_ipprec) allows to mark self-originated + sFlow, NetFlow and BGP datagrams with the supplied IP precedence + value. + + peer_src_ip (IP address of the NetFlow emitter, agent ID of the + sFlow emitter) and peer_dst_ip (BGP next-hop) can now be filled + from NetFlow/sFlow protocols data other than BGP. To activate the + feature nfacctd_as_new/sfacctd_as_new have to be 'false' (default + value), 'true' or 'file'. + + print plugin: introduced support for Comma-Separated Values (CSV) + output in addition to formatted-text. A new print_output feature + allows to switch between the two. + + pmacctd: improved 802.1ad support. While recursing, outer VLAN is + always reported as value of the 'vlan' primitive. + ! fix, pmacctd: 802.1p was kept integral part of the 'vlan' value. + Now a 0x0FFF mask is applied in order to return only the VLAN ID. + ! fix, pkt_handlers.c: added trailing '\0' symbol when truncating + AS-PATH and BGP community strings due to length constraints. + ! fix, sql_common.c: maximum SQL writers warning message was never + reached unless a recovery method is specifited. Thanks to Sergio + Charpinel Jr for reporting the issue. + ! fix, MySQL and PostgreSQL plugins: PGRES_TUPLES_OK (PostgreSQL) + and errno 1050 (MySQL) are now considered valid return codes when + dynamic tables are involved (ie. sql_table_schema). Thanks to + Sergio Charpinel Jr for his support. + ! fix, BGP daemon: pkt_bgp_primitives struct has been explicitely + 64-bit aligned. Mis-alignment was causing crashes when buffering + was enabled (plugin_buffer_size). Verified on Solaris/sparc. + 0.12.1 -- 07-04-2010 + Input/output interfaces (SNMP indexes) have now been implemented natively; it's therefore not required anymore to pass through the diff -Nru pmacct-0.12.1/CONFIG-KEYS pmacct-0.12.5/CONFIG-KEYS --- pmacct-0.12.1/CONFIG-KEYS 2010-04-05 19:07:24.000000000 +0000 +++ pmacct-0.12.5/CONFIG-KEYS 2010-11-07 15:11:11.000000000 +0000 @@ -28,7 +28,7 @@ DESC: daemonizes the process (default: false). KEY: aggregate (-c) -VALUES: [src_mac, dst_mac, vlan, src_host, dst_host, src_net, dst_net, src_mask, +VALUES: [src_mac, dst_mac, vlan, cos, src_host, dst_host, src_net, dst_net, src_mask, dst_mask, src_as, dst_as, src_port, dst_port, tos, proto, none, sum_mac, sum_host, sum_net, sum_as, sum_port, flows, tag, tag2, class, tcpflags, in_iface, out_iface, std_comm, ext_comm, as_path, peer_src_ip, peer_dst_ip, @@ -50,16 +50,15 @@ sum_ are compound primitives which join together both inbound and outbound traffic into a single aggregate. The 'none' primitive allows to make an unique aggregate which accounts for the grand total of traffic flowing - through a specific interface. 'tag' and 'tag2' enable reception of tags when + through a specific interface. 'tag' and 'tag2' enable generation of tags when tagging engines (pre_tag_map, post_tag) are in use. 'class' enables reception of L7 traffic classes when Packet/Flow Classification engine (classifiers) is in use. (default: src_host). -NOTES: * tag2, src_as_path, src_std_comm, src_ext_comm, src_local_pref and src_med - primitives are not part of any default pmacct SQL table. When considering - their use, they have to be manually added to the selected SQL schema and to - the indexing. Read further in the documentation of the database of choice - (ie. 'sql/README.mysql') and take as reference the 'sql/README.agent_id2' - document. +NOTES: * Some primitives (ie. tag2, src_as_path, src_std_comm, src_ext_comm, src_med + and src_local_pref primitives) are not part of any default SQL table schema + shipped with pmacct. Always check out documentation related to the RDBMS in + use (ie. 'sql/README.mysql') which will point you to extra primitive-related + documentation, if required. KEY: aggregate_filter [NO_GLOBAL] DESC: Per-plugin filtering applied against the original packet or flow. Aggregation @@ -80,7 +79,7 @@ turn, allows to filter tags). You will also need to force fragmentation handling in the specific case in which a) none of the 'aggregate' directives is including L4 primitives (ie. src_port, dst_port) but b) an 'aggregate_filter' runs a filter - which requires dealing with L4 primitives. For further informations, refer to the + which requires dealing with L4 primitives. For further information, refer to the 'pmacctd_force_frag_handling' directive. KEY: pcap_filter (like tcpdump syntax) [GLOBAL, NO_NFACCTD] @@ -104,14 +103,17 @@ increased. KEY: plugins (-P) -VALUES: [ memory | print | mysql | pgsql | sqlite3 | nfprobe | sfprobe ] +VALUES: [ memory | print | mysql | pgsql | sqlite3 | nfprobe | sfprobe | tee ] DESC: plugins to be enabled. SQL plugins are available only if configured and compiled. 'memory' enables the use of a memory table as backend; then, a client tool, 'pmacct', can fetch its content; mysql, pgsql and sqlite3 enable the use of respectively MySQL, PostgreSQL and SQLite 3.x tables to store data. 'print' prints aggregates to stdout in a nicely formatted way. 'nfprobe' acts as a NetFlow agent and exports collected data via NetFlow v1/v5/v9 datagrams to a remote collector. 'sfprobe' acts as a sFlow - agent and exports collected data via sFlow v5 datagrams to a remote collector. + agent and exports collected data via sFlow v5 datagrams to a remote collector. Both + 'nfprobe' and 'sfprobe' apply only to 'pmacctd' and 'uacctd' daemons. 'tee' acts as + a replicator for NetFlow/sFlow data (also transparent); it applies to 'nfacctd' and + 'sfacctd' daemons only. Plugins can be either anonymous or named; configuration directives can be either global or bounded to a specific named plugin. An anonymous plugin is declared as 'plugins: mysql' whereas a named plugin is declared as 'plugins: mysql[name]'. Then, @@ -282,7 +284,7 @@ %Y The year as a decimal number including the century. Time-related variables REQUIRE 'sql_history' to be in place in order to work correctly - (refer also to their entry in this document for further informations). Moreover, if the + (refer also to their entry in this document for further information). Moreover, if the 'sql_table_schema' directive is not specified, tables are expected to be already in place. Let's proceed with an example to split accounted data among multiple tables basing on the day of the week: @@ -321,7 +323,7 @@ closed in a 'ring' fashion (e.g., the days of the week) but 'open' (e.g., current date). KEY: sql_table_version (-v) -VALUES [ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] +VALUES [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] DESC: defines the version of the SQL table. SQL table versioning was introduced to achieve two goals: a) make tables work out-of-the-box for the SQL beginners, smaller installations and quick try-outs; and in this context b) to allow introduction of new features over @@ -597,9 +599,13 @@ KEY: print_markers VALUES: [true|false] -DESC: this directive applies only to 'print' plugin. Enables the use of START/END markers each time - purging aggregates to 'stdout'. Start marker includes also informations about current timeslot - and refresh time (default: false). +DESC: Enables the use of START/END markers each time data is written to 'stdout'. Start marker returns + additional information about current time-bin and configured refresh time (default: false). + +KEY: print_output +VALUES: [ formatted | csv ] +DESC: Defines the print plugin output format. 'formatted' enables tabular output; 'csv' is to enable + comma-separated values format, suitable for injection into 3rd party tools. (default: formatted) KEY: nfacctd_port (-l) [GLOBAL, NO_PMACCTD] DESC: defines the UDP port where to bind the 'nfacctd' daemon (default: 2100). @@ -637,18 +643,22 @@ source IP address. pmacctd and uacctd can't grasp ASNs from any protocol: 'false' (for backward compatibility), 'true' and 'file' expect a 'networks_file' to be defined. 'bgp' just works as described above. - (default: false) + Under nfacctd and sfacctd this feature also influences 'peer_src_ip' and 'peer_dst_ip': if + 'false', 'true' or 'file' values are taken from NetFlow and sFlow datagrams respectively; + if 'bgp' values are looked up against the BGP RIB of the peer from which the NetFlow datagram + was received (or mapped to). (default: false) -KEY: [ nfacctd_net | sfacctd_net | pmacctd_net | uacctd_net ] [GLOBAL] +KEY: [ nfacctd_net | sfacctd_net | pmacctd_net | uacctd_net ] VALUES: [ netflow | sflow | mask | file | bgp ] DESC: Determines the source of data to perform network aggregation - directly influencing 'src_net', 'dst_net', 'src_mask' and 'dst_mask' primitives. 'netflow' and 'sflow' use netmask values carried within NetFlow and sFlow protocols; valid only in conjunction with nfacctd and sfacctd. 'mask' selects a defined networks_mask; 'file' selects a defined networks_file; 'bgp' uses - netmask values carried within BGP protocol (not yet implemented). If this directive is not - specified, the daemon falls back to backward compatibility mode, hence enabling 'mask', if a - networks_mask is defined, and 'file', if a networks_file. If both are defined, the outcome - will be the intersection of their definitions. (default: 'mask', 'file') + netmask values carried within BGP protocol. If this directive is not specified, the daemon + falls back to backward compatibility mode, hence enabling 'mask', if a networks_mask is + defined, and 'file', if a networks_file. If both are defined, the outcome will be the + intersection of their definitions. (default: nfacctd: 'netflow'; sfacctd: 'sflow'; pmacctd + and uacctd: 'mask', 'file') KEY: [ nfacctd_mcast_groups | sfacctd_mcast_groups ] [GLOBAL, NO_PMACCTD] DESC: defines one or more IPv4/IPv6 multicast groups to be joined by the daemon. If more groups are @@ -757,7 +767,7 @@ DESC: defines how long a flow could remain inactive (ie. no packets belonging to such flow are received) before considering it expired. The value is expected in seconds. (default: 60 secs) -KEY: [ pmacctd_ext_sampling_rate | uacctd_ext_sampling_rate nfacctd_ext_sampling_rate | +KEY: [ pmacctd_ext_sampling_rate | uacctd_ext_sampling_rate | nfacctd_ext_sampling_rate | sfacctd_ext_sampling_rate ] [GLOBAL] flags pmacctd that captured traffic is being sampled at the specified rate. Such rate can then be renormalized by using 'pmacctd_renormalize' or otherwise is propagated by the NetFlow/sFlow @@ -781,7 +791,7 @@ KEY: [ sfacctd_renormalize | nfacctd_renormalize | pmacctd_renormalize | uacctd_renormalize ] (-R) VALUES: [true|false] -DESC: automatically renormalizes byte/packet counters value basing on informations acquired from +DESC: automatically renormalizes byte/packet counters value basing on information acquired from either the NetFlow data unit or sFlow packet. In particular, it allows to deal with scenarios in which multiple interfaces have been configured at different sampling rates. The feature also calculates an effective sampling rate (sFlow only) which could differ from the configured one - @@ -861,7 +871,8 @@ KEY: nfprobe_source_ip DESC: defines the local IP address from which NetFlow dagagrams are to be exported. Only a numerical IPv4/IPv6 address is expected. The supplied IP address is required to be already configured on - one of the interfaces. (default: IP address is selected by the OS) + one of the interfaces. This parameter is also required for graceful encoding of NetFlow v9 + option scoping. (default: IP address is selected by the OS) KEY: nfprobe_version VALUES: [5,9] @@ -884,6 +895,29 @@ enable this feature are: a) one of the nfacctd_as_new/sfacctd_as_new/pmacctd_as/uacctd_as set to 'bgp' and b) a fully functional BGP daemon (bgp_daemon). (default: false) +KEY: [ nfprobe_ipprec | sfprobe_ipprec ] +DESC: marks self-originated NetFlow (nfprobe) and sFlow (sfprobe) messages with the supplied IP + precedence value. (default: 0) + +KEY: [ nfprobe_direction | sfprobe_direction ] +VALUES: [in,out,tag,tag2] +DESC: defines traffic direction. Can be statically defined via 'in' and 'out' keywords. It can also + be dynamically determined via lookup to either 'tag' or 'tag2' values. Tag value of 1 will be + mapped to 'in' direction, whereas tag value of 2 will be mapped to 'out'. The idea underlying + tag lookups is that pre_tag_map supports, among the other features, 'filter' matching against + a supplied tcpdump-like filter expression; doing so against L2 primitives (ie. source or + destination MAC addresses) allows to dynamically determine traffic direction (see example at + 'examples/pretag.map.example') (default: none) + +KEY: [ nfprobe_ifindex | sfprobe_ifindex ] +VALUES: [tag,tag2,<1-4294967295>] +DESC: associates an interface index (ifIndex) to a given nfprobe or sfprobe plugin. This is meant as + an add-on to [ns]probe_direction directive, ie. when multiplexing mirrored traffic from different + sources on the same interface (ie. split by VLAN). Can be statically defined via a 32-bit integer + or semi-dynamically determined via lookup to either 'tag' or 'tag2' values (read full elaboration + on [ns]probe_direction directive). This definition will be also always overridden whenever the + ifIndex can be determined dynamically (ie. via ULOG framework). + KEY: sfprobe_receiver DESC: defines the remote IP address/hostname and port to which sFlow dagagrams are to be exported. The value is expected to be in the usual form 'address:port'. (default: 127.0.0.1:6343) @@ -894,6 +928,9 @@ KEY: sfprobe_agentsubid DESC: sets the value of agentSubId field inside the sFlow datagram header. +KEY: sfprobe_ifspeed +DESC: statically associates an interface speed to a given sfprobe plugin. (default: 100000000) + KEY: bgp_daemon VALUES: [true|false] DESC: enables the skinny BGP daemon thread. This feature requires the package to be supporting multi- @@ -913,6 +950,9 @@ KEY: bgp_daemon_port DESC: binds the BGP daemon to a port different from the standard BGP port: 179/tcp. (default: 179) +KEY: bgp_daemon_ipprec +DESC: marks self-originated BGP messages with the supplied IP precedence value. (default: 0) + KEY: bgp_daemon_max_peers DESC: sets the maximum number of neighbors the BGP daemon can peer to. Upon reaching of the limit, no more BGP sessions can be established. Differently from routers BGP neighbors don't need to @@ -1023,14 +1063,15 @@ 'examples/is_symmetric.map.example'. KEY: bgp_agent_map -DESC: full pathname to a file to map source IP addresses of NetFlow/sFlow agents to BGP peers' - ones. It is particularly aimed as a resource-savy alternative to have N agents but only a - restricted number of BGP peers (ie. a BGP RR), in case of simpler topologies (ie. hub-and- - spoke) or scenarios (ie. single-homed). It can also be viewed as a temporary workaround to - certain situations. pmacctd, uacctd daemons are required to use a bgp_agent_map with up to - two "catch-all" entries - working in a primary/backup fashion (see agent_to_peer.map in the - examples section): this is because these daemons do not have a NetFlow/sFlow source address - to match to. Number of map entries (by default 384) can be modified via pre_tag_map_entries. +DESC: full pathname to a file to map source IP address of NetFlow agents and AgentID of sFlow + agents to source IP address or Router ID of BGP peers. This is particularly aimed as a + resource-savy alternative to have N agents but only a restricted number of BGP peers (ie. + a BGP RR), in case of simpler topologies (ie. hub-and- spoke) or scenarios (ie. single- + homed). It can also be viewed as a temporary workaround to certain situations. pmacctd, + uacctd daemons are required to use a bgp_agent_map with up to two "catch-all" entries - + working in a primary/backup fashion (see agent_to_peer.map in the examples section): + this is because these daemons do not have a NetFlow/sFlow source address to match to. + Number of map entries (by default 384) can be modified via pre_tag_map_entries. KEY: bgp_follow_default DESC: expects positive number value which instructs how many times a default route, if any, can @@ -1069,8 +1110,25 @@ KEY: bgp_daemon_allow_file [GLOBAL] DESC: full pathname to a file containing the list of IP addresses (one for each line) allowed to establish a BGP session packets to the BGP thread. Current syntax does not implement - network masks but only individual IP addresses. The Allow List is intended to be small; - firewall rules should be preferred to long ACLs. (default: allow all) + network masks but only individual IP addresses. (default: allow all) + +KEY: bgp_daemon_md5_file [GLOBAL] +DESC: full pathname to a file containing the BGP peers (IP address only, one for each line) + and their corresponding MD5 passwords in CSV format (ie. 10.15.0.1, arealsmartpwd). + BGP peers not making use of a MD5 password should not be listed. The maximum number + of peers supported is 8192. For a sample map look in: 'examples/bgp_md5.lst.example' + The feature was tested working against a 2.6.32 Linux kernel. (default: no password) + +KEY: bgp_table_peer_buckets [GLOBAL] +VALUES: [ 1-1000 ] +DESC: From version 0.12.4, a shared BGP RIB is worked out from announcements sent by all BGP + peers. Routing information related to BGP prefixes is kept per-peer in order to simulate + a multi-RIB environment and is internally structured as an hash with conflict chains. + This parameter sets the number of buckets of such hash structure; the value is directly + related to the number of expected BGP peers, should never exceed such amount and is best + set to 1/10 of the expected number of peers. The default value proved to work fine up to + aprox 100 BGP peers in lab. More buckets means better CPU usage but also increased memory + footprint - and vice-versa. (default: 13) KEY: uacctd_group DESC: Sets the Linux Netlink ULOG multicast group to be joined. (default: 1) @@ -1092,3 +1150,25 @@ GTP, GPRS tunnelling protocol. Expects as option the UDP port identifying the protocol. tunnel_0: gtp, +KEY: tee_receiver +DESC: defines remote IP address and port to which NetFlow/sFlow dagagrams are to be replicated + to. The value is expected to be in the usual form 'address:port'. This key is mandatory + for a 'tee' plugin instance and no default value is set in order to prevent loops. + +KEY: tee_source_ip +DESC: defines the local IP address from which NetFlow/sFlow dagagrams are to be replicate from. + Only a numerical IPv4/IPv6 address is expected. The supplied IP address is required to be + already configured on one of the interfaces. Value is ignored when transparent replication + is enabled. (default: IP address is selected by the OS) + +KEY: tee_transparent +VALUES: [true|false] +DESC: Enables transparent replication mode. It essentially spoofs the source IP address to the + original sender of the datagram. It requires super-user permissions. (default: false) + +KEY: [ xlate_src | xlate_dst ] +VALUES: [true|false] +DESC: Copies NAT L3/L4 field values in place of the original ones (ie. src_host, src_port, + src_net, dst_host, dst_port, dst_net) when available; alternatively it falls back to + original values. At time of writing only IPFIX and Cisco ASA NetFlow v9 (NSEL) have + support for this. (default: false) diff -Nru pmacct-0.12.1/configure pmacct-0.12.5/configure --- pmacct-0.12.1/configure 2010-04-07 06:35:51.000000000 +0000 +++ pmacct-0.12.5/configure 2010-12-28 16:26:21.000000000 +0000 @@ -733,7 +733,7 @@ PACKAGE=pmacctd -VERSION=0.12.1 +VERSION=0.12.5 if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } @@ -3604,7 +3604,7 @@ ;; esac -LIBS="${LIBS} -lnfprobe_plugin -Lnfprobe_plugin/ -lsfprobe_plugin -Lsfprobe_plugin/ -lbgp -Lbgp/" +LIBS="${LIBS} -lnfprobe_plugin -Lnfprobe_plugin/ -lsfprobe_plugin -Lsfprobe_plugin/ -lbgp -Lbgp/ -ltee_plugin -Ltee_plugin/" echo " PLATFORM ..... : `uname -m` @@ -3741,8 +3741,8 @@ trap 'rm -fr `echo " Makefile \ src/Makefile src/nfprobe_plugin/Makefile \ - src/sfprobe_plugin/Makefile - src/bgp/Makefile " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 + src/sfprobe_plugin/Makefile src/bgp/Makefile \ + src/tee_plugin/Makefile " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then diff -Nru pmacct-0.12.1/configure.in pmacct-0.12.5/configure.in --- pmacct-0.12.1/configure.in 2010-04-07 06:35:47.000000000 +0000 +++ pmacct-0.12.5/configure.in 2010-12-28 16:26:17.000000000 +0000 @@ -1,8 +1,8 @@ dnl Process this file with autoconf to produce a configure script. dnl configuration file for pmacct -AC_INIT([src/pmacctd.c], [0.12.1], [paolo@pmacct.net]) -AM_INIT_AUTOMAKE([pmacctd], [0.12.1]) +AC_INIT([src/pmacctd.c], [0.12.5], [paolo@pmacct.net]) +AM_INIT_AUTOMAKE([pmacctd], [0.12.5]) AC_PREFIX_DEFAULT([/usr/local]) dnl Checks for programs. @@ -906,7 +906,7 @@ ;; esac -LIBS="${LIBS} -lnfprobe_plugin -Lnfprobe_plugin/ -lsfprobe_plugin -Lsfprobe_plugin/ -lbgp -Lbgp/" +LIBS="${LIBS} -lnfprobe_plugin -Lnfprobe_plugin/ -lsfprobe_plugin -Lsfprobe_plugin/ -lbgp -Lbgp/ -ltee_plugin -Ltee_plugin/" echo " PLATFORM ..... : `uname -m` @@ -930,5 +930,5 @@ AC_SUBST([EXTRABIN]) AC_OUTPUT([ Makefile \ src/Makefile src/nfprobe_plugin/Makefile \ - src/sfprobe_plugin/Makefile - src/bgp/Makefile ]) + src/sfprobe_plugin/Makefile src/bgp/Makefile \ + src/tee_plugin/Makefile ]) diff -Nru pmacct-0.12.1/debian/changelog pmacct-0.12.5/debian/changelog --- pmacct-0.12.1/debian/changelog 2011-12-15 01:51:15.000000000 +0000 +++ pmacct-0.12.5/debian/changelog 2012-02-14 07:16:50.000000000 +0000 @@ -1,20 +1,39 @@ -pmacct (0.12.1-1ubuntu1) precise; urgency=low +pmacct (0.12.5-4) unstable; urgency=low - * d/control: Build-Depend on libmysqlclient-dev to pick up latest - version of libmysqlclient. + * Revert initscripts stop command to use SIGINT instead of SIGTERM. as part of #659710. - -- Clint Byrum Wed, 14 Dec 2011 17:50:56 -0800 + -- Jamie Wilkinson Tue, 14 Feb 2012 07:16:03 +0000 + +pmacct (0.12.5-3) unstable; urgency=low + + * Add initscripts for nfacctd, sfacctd and uacctd. (Closes: #503285, #659710) + * Rename the pmacct initscript and default to "pmacctd". + * Fix permissions on config files to not be world readable. (Closes: #579535) + + -- Jamie Wilkinson Tue, 14 Feb 2012 07:01:36 +0000 + +pmacct (0.12.5-2) unstable; urgency=low + + * Build a 64bit binary and enable threads. (Closes: #659711) + + -- Jamie Wilkinson Tue, 14 Feb 2012 02:10:03 +0000 + +pmacct (0.12.5-1) unstable; urgency=low + + * New upstream release. + * Set extend-diff-ignore in debian/source/options to ignore changeable files. (Closes: #643250) + * Fix FTBFS on kFreeBSD. Thanks Robert Millan! (Closes: #647661, #617570) + * Build-depend on the lastest libmysqlclient-dev. Thanks Clint Byrum! (Closes: #652136) + * Depend on psmisc so that stopping the daemon works. (Closes: #571548) + * Include manpage for pmacct. Thanks Mats Erik Andersson! (Closes: #617558) + + -- Jamie Wilkinson Fri, 10 Feb 2012 02:34:49 +0000 pmacct (0.12.1-1) unstable; urgency=low * New upstream release. - * Bumped standards version to 3.8.4. - * Added ${misc:Depends} to the dependencies line as requested by debhelper. - * Switch to dpkg-source 3.0 (quilt) format. - * Add initscript dependency on $remote_fs for /usr, the location of the pmacctd daemon. - * Remove exclusion of .arch directories from dh_installdocs as arch is way obsolete now. - -- Jamie Wilkinson Thu, 08 Apr 2010 21:00:14 +1000 + -- Jamie Wilkinson Thu, 08 Apr 2010 20:29:51 +1000 pmacct (0.12.0-1) unstable; urgency=low diff -Nru pmacct-0.12.1/debian/control pmacct-0.12.5/debian/control --- pmacct-0.12.1/debian/control 2011-12-15 01:51:18.000000000 +0000 +++ pmacct-0.12.5/debian/control 2012-02-10 02:33:51.000000000 +0000 @@ -1,14 +1,13 @@ Source: pmacct Section: net Priority: optional -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Jamie Wilkinson +Maintainer: Jamie Wilkinson Build-Depends: debhelper (>= 7), zlib1g-dev, libpcap-dev, libpq-dev, libmysqlclient-dev, libsqlite3-dev -Standards-Version: 3.8.4 +Standards-Version: 3.8.3 Package: pmacct Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, iproute +Depends: ${shlibs:Depends}, net-tools [linux-any] | freebsd-net-tools [kfreebsd-any], psmisc Description: promiscuous mode traffic accountant pmacct is a tool designed to gather traffic information (bytes and number of packets) by listening on a promiscuous interface or for Netflow data, diff -Nru pmacct-0.12.1/debian/nfacctd.conf pmacct-0.12.5/debian/nfacctd.conf --- pmacct-0.12.1/debian/nfacctd.conf 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/nfacctd.conf 2012-02-14 06:41:09.000000000 +0000 @@ -0,0 +1,29 @@ +! nfacctd configuration +! +! +! +daemonize: true +pidfile: /var/run/nfacctd.pid +syslog: daemon +! +! interested in in and outbound traffic +aggregate: src_host,dst_host +! on this network +pcap_filter: net 127.0.0.0/8 +! on this interface +interface: lo +! +! storage methods +!plugins: pgsql +!sql_host: localhost +!sql_passwd: +! refresh the db every minute +!sql_refresh_time: 60 +! reduce the size of the insert/update clause +!sql_optimize_clauses: true +! accumulate values in each row for up to an hour +!sql_history: 1h +! create new rows on the minute, hour, day boundaries +!sql_history_roundoff: mhd +! in case of emergency, log to this file +!sql_recovery_logfile: /var/lib/pmacct/nfacctd_recovery_log diff -Nru pmacct-0.12.1/debian/patches/debian-changes-0.12.1-1 pmacct-0.12.5/debian/patches/debian-changes-0.12.1-1 --- pmacct-0.12.1/debian/patches/debian-changes-0.12.1-1 2010-04-08 11:46:36.000000000 +0000 +++ pmacct-0.12.5/debian/patches/debian-changes-0.12.1-1 1970-01-01 00:00:00.000000000 +0000 @@ -1,4452 +0,0 @@ -Description: Upstream changes introduced in version 0.12.1-1 - This patch has been created by dpkg-source during the package build. - Here's the last changelog entry, hopefully it gives details on why - those changes were made: - . - pmacct (0.12.1-1) unstable; urgency=low - . - * New upstream release. - * Bumped standards version to 3.8.4. - * Added ${misc:Depends} to the dependencies line as requested by debhelper. - * Switch to dpkg-source 3.0 (quilt) format. - * Add initscript dependency on $remote_fs for /usr, the location of the pmacctd daemon. - * Remove exclusion of .arch directories from dh_installdocs as arch is way obsolete now. - . - The person named in the Author field signed this changelog entry. -Author: Jamie Wilkinson - ---- -The information above should follow the Patch Tagging Guidelines, please -checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here -are templates for supplementary fields that you might want to add: - -Origin: , -Bug: -Bug-Debian: http://bugs.debian.org/ -Forwarded: -Reviewed-By: -Last-Update: - ---- pmacct-0.12.1.orig/configure -+++ pmacct-0.12.1/configure -@@ -1,7 +1,7 @@ - #! /bin/sh - - # Guess values for system-dependent variables and create Makefiles. --# Generated automatically using autoconf version 2.13 -+# Generated automatically using autoconf version 2.13 - # Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. - # - # This configure script is free software; the Free Software Foundation -@@ -1274,9 +1274,9 @@ echo "configure:1274: checking for __pro - cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then -@@ -1293,7 +1293,7 @@ else - fi - rm -f conftest* - -- -+ - echo $ac_n "checking for extra flags needed to export symbols""... $ac_c" 1>&6 - echo "configure:1299: checking for extra flags needed to export symbols" >&5 - if test "x$ac_cv_prog_gcc" = xyes ; then -@@ -1314,7 +1314,7 @@ int main() { - EOF - if { (eval echo configure:1316: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* -- echo "$ac_t""--export-dynamic" 1>&6 -+ echo "$ac_t""--export-dynamic" 1>&6 - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 -@@ -1330,18 +1330,18 @@ int main() { - EOF - if { (eval echo configure:1332: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* -- echo "$ac_t""-Bexport" 1>&6 -+ echo "$ac_t""-Bexport" 1>&6 - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - echo "$ac_t""none" 1>&6 -- LDFLAGS="${save_ldflags}" -- -+ LDFLAGS="${save_ldflags}" -+ - fi - rm -f conftest* -- -- -+ -+ - fi - rm -f conftest* - ;; -@@ -1497,17 +1497,17 @@ if test "${enable_l2+set}" = set; then - cat >> confdefs.h <<\EOF - #define HAVE_L2 1 - EOF -- -+ - else - echo "$ac_t""yes" 1>&6 - fi -- -+ - else - echo "$ac_t""no" 1>&6 - cat >> confdefs.h <<\EOF - #define HAVE_L2 1 - EOF -- -+ - - fi - -@@ -1517,7 +1517,7 @@ echo "configure:1517: checking whether t - # Check whether --enable-ipv6 or --disable-ipv6 was given. - if test "${enable_ipv6+set}" = set; then - enableval="$enable_ipv6" -- -+ - echo "$ac_t""yes" 1>&6 - for ac_func in inet_pton - do -@@ -1568,7 +1568,7 @@ if eval "test \"`echo '$ac_cv_func_'$ac_ - cat >> confdefs.h <&6 - fi -@@ -1627,7 +1627,7 @@ if eval "test \"`echo '$ac_cv_func_'$ac_ - cat >> confdefs.h <&6 - fi -@@ -1649,7 +1649,7 @@ EOF - EOF - - ;; -- esac -+ esac - else - echo "$ac_t""no" 1>&6 - ipv6support="no" -@@ -1657,13 +1657,13 @@ else - fi - - --if test $ipv6support = "yes"; then -+if test $ipv6support = "yes"; then - echo $ac_n "checking whether to enable IPv4-mapped IPv6 sockets ""... $ac_c" 1>&6 - echo "configure:1663: checking whether to enable IPv4-mapped IPv6 sockets " >&5 - # Check whether --enable-v4-mapped or --disable-v4-mapped was given. - if test "${enable_v4_mapped+set}" = set; then - enableval="$enable_v4_mapped" -- -+ - if test x$enableval = x"yes" ; then - cat >> confdefs.h <<\EOF - #define V4_MAPPED 1 -@@ -1672,9 +1672,9 @@ EOF - echo "$ac_t""yes" 1>&6 - else - echo "$ac_t""no" 1>&6 -- fi -+ fi - else -- -+ - case $host_os in - *FreeBSD*|*NetBSD*|*OpenBSD*) - echo "$ac_t""no" 1>&6 -@@ -1686,7 +1686,7 @@ EOF - - echo "$ac_t""yes" 1>&6 - ;; -- esac -+ esac - - fi - -@@ -1695,8 +1695,8 @@ fi - # Check whether --with-pcap-includes or --without-pcap-includes was given. - if test "${with_pcap_includes+set}" = set; then - withval="$with_pcap_includes" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -1705,14 +1705,14 @@ if test "${with_pcap_includes+set}" = se - INCLUDES="${INCLUDES} -I$withval" - PCAPINCLS=$withval - PCAPINCLUDESFOUND=1 -- -+ - fi - - - if test x"$PCAPINCLS" != x""; then - echo $ac_n "checking your own pcap includes""... $ac_c" 1>&6 - echo "configure:1715: checking your own pcap includes" >&5 -- if test -r $PCAPINCLS/pcap.h; then -+ if test -r $PCAPINCLS/pcap.h; then - echo "$ac_t""ok" 1>&6 - cat >> confdefs.h <<\EOF - #define HAVE_PCAP_H 1 -@@ -1720,7 +1720,7 @@ EOF - - else - echo "$ac_t""no" 1>&6 -- { echo "configure: error: ERROR: missing pcap.h in $PCAPINCLS" 1>&2; exit 1; } -+ { echo "configure: error: ERROR: missing pcap.h in $PCAPINCLS" 1>&2; exit 1; } - fi - fi - -@@ -1748,7 +1748,7 @@ EOF - cat >> confdefs.h <<\EOF - #define HAVE_PCAP_H 1 - EOF -- -+ - elif test -r /usr/local/include/pcap/pcap.h; then - echo "$ac_t""found in /usr/local/include" 1>&6 - INCLUDES="${INCLUDES} -I/usr/local/include" -@@ -1767,8 +1767,8 @@ fi - # Check whether --with-pcap-libs or --without-pcap-libs was given. - if test "${with_pcap_libs+set}" = set; then - withval="$with_pcap_libs" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -1777,7 +1777,7 @@ if test "${with_pcap_libs+set}" = set; t - LIBS="${LIBS} -L$withval" - PCAPLIB=$withval - PCAPLIBFOUND=1 -- -+ - fi - - -@@ -1870,9 +1870,9 @@ EOF - - else - echo "$ac_t""no" 1>&6 --{ echo "configure: error: -- ERROR: missing pcap library. Refer to: http://www.tcpdump.org/ -- " 1>&2; exit 1; } -+{ echo "configure: error: -+ ERROR: missing pcap library. Refer to: http://www.tcpdump.org/ -+" 1>&2; exit 1; } - fi - - -@@ -1914,7 +1914,7 @@ if eval "test \"`echo '$ac_cv_lib_'$ac_l - cat >> confdefs.h <<\EOF - #define PCAP_7 1 - EOF -- -+ - else - echo "$ac_t""no" 1>&6 - fi -@@ -2054,8 +2054,8 @@ if test "${enable_mysql+set}" = set; the - # Check whether --with-mysql-libs or --without-mysql-libs was given. - if test "${with_mysql_libs+set}" = set; then - withval="$with_mysql_libs" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2064,9 +2064,9 @@ if test "${with_mysql_libs+set}" = set; - LIBS="${LIBS} -L$withval" - MYSQLLIB=$withval - MYSQLLIBFOUND=1 -- -+ - fi -- -+ - - if test x"$MYSQLLIB" != x""; then - echo $ac_n "checking your own MySQL client library""... $ac_c" 1>&6 -@@ -2094,7 +2094,7 @@ echo "configure:2085: checking default l - LIBS="${LIBS} -L/usr/local/lib/mysql" - echo "$ac_t""found in /usr/local/lib/mysql" 1>&6 - MYSQLLIBFOUND=1 -- else -+ else - echo "$ac_t""not found" 1>&6 - fi - fi -@@ -2145,25 +2145,25 @@ EOF - - else - echo "$ac_t""no" 1>&6 --{ echo "configure: error: -+{ echo "configure: error: - ERROR: missing MySQL client library. Refer to: http://www.mysql.com/ - " 1>&2; exit 1; } - fi - -- else -+ else - LIBS="${LIBS} -lmysqlclient" - case "$host_os" in - Sun*) - LIBS="${LIBS} -lrt" - ;; - esac -- fi -+ fi - - # Check whether --with-mysql-includes or --without-mysql-includes was given. - if test "${with_mysql_includes+set}" = set; then - withval="$with_mysql_includes" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2172,7 +2172,7 @@ if test "${with_mysql_includes+set}" = s - INCLUDES="${INCLUDES} -I$withval" - MYSQLINCLUDES=$withval - MYSQLINCLUDESFOUND=1 -- -+ - fi - - -@@ -2193,7 +2193,7 @@ EOF - fi - fi - -- if test x"$MYSQLINCLUDESFOUND" = x""; then -+ if test x"$MYSQLINCLUDESFOUND" = x""; then - echo $ac_n "checking default locations for mysql.h""... $ac_c" 1>&6 - echo "configure:2199: checking default locations for mysql.h" >&5 - if test -r /usr/include/mysql/mysql.h; then -@@ -2251,7 +2251,7 @@ else - echo "$ac_t""no" 1>&6 - { echo "configure: error: ERROR: missing MySQL headers" 1>&2; exit 1; } - fi -- -+ - fi - - cat >> confdefs.h <<\EOF -@@ -2259,12 +2259,12 @@ fi - EOF - - PLUGINS="${PLUGINS} mysql_plugin.c" -- EXTRABIN="${EXTRABIN} pmmyplay" -+ EXTRABIN="${EXTRABIN} pmmyplay" - ;; - no) - echo "$ac_t""no" 1>&6 - ;; -- esac -+ esac - else - echo "$ac_t""no" 1>&6 - fi -@@ -2283,8 +2283,8 @@ if test "${enable_pgsql+set}" = set; the - # Check whether --with-pgsql-libs or --without-pgsql-libs was given. - if test "${with_pgsql_libs+set}" = set; then - withval="$with_pgsql_libs" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2293,9 +2293,9 @@ if test "${with_pgsql_libs+set}" = set; - LIBS="${LIBS} -L$withval" - PGSQLLIB=$withval - PGSQLLIBFOUND=1 -- -+ - fi -- -+ - - if test x"$PGSQLLIB" != x""; then - echo $ac_n "checking your own PostgreSQL client library""... $ac_c" 1>&6 -@@ -2322,7 +2322,7 @@ echo "configure:2314: checking default l - LIBS="${LIBS} -L/usr/local/pgsql/lib" - echo "$ac_t""found in /usr/local/pgsql/lib" 1>&6 - PGSQLLIBFOUND=1 -- else -+ else - echo "$ac_t""not found" 1>&6 - fi - fi -@@ -2373,20 +2373,20 @@ EOF - - else - echo "$ac_t""no" 1>&6 --{ echo "configure: error: -+{ echo "configure: error: - ERROR: missing PQ library. Refer to: http://www.postgresql.org/ - " 1>&2; exit 1; } - fi - -- else -+ else - LIBS="${LIBS} -lpq" -- fi -+ fi - - # Check whether --with-pgsql-includes or --without-pgsql-includes was given. - if test "${with_pgsql_includes+set}" = set; then - withval="$with_pgsql_includes" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2395,7 +2395,7 @@ if test "${with_pgsql_includes+set}" = s - INCLUDES="${INCLUDES} -I$withval" - PGSQLINCLUDES=$withval - PGSQLINCLUDESFOUND=1 -- -+ - fi - - -@@ -2410,7 +2410,7 @@ echo "configure:2405: checking your own - fi - fi - -- if test x"$PGSQLINCLUDESFOUND" = x""; then -+ if test x"$PGSQLINCLUDESFOUND" = x""; then - echo $ac_n "checking default locations for libpq-fe.h""... $ac_c" 1>&6 - echo "configure:2416: checking default locations for libpq-fe.h" >&5 - if test -r /usr/include/libpq-fe.h; then -@@ -2464,7 +2464,7 @@ else - echo "$ac_t""no" 1>&6 - { echo "configure: error: ERROR: missing PostgreSQL headers" 1>&2; exit 1; } - fi -- -+ - fi - - cat >> confdefs.h <<\EOF -@@ -2472,12 +2472,12 @@ fi - EOF - - PLUGINS="${PLUGINS} pgsql_plugin.c" -- EXTRABIN="${EXTRABIN} pmpgplay" -+ EXTRABIN="${EXTRABIN} pmpgplay" - ;; - no) - echo "$ac_t""no" 1>&6 - ;; -- esac -+ esac - else - echo "$ac_t""no" 1>&6 - fi -@@ -2496,8 +2496,8 @@ if test "${enable_sqlite3+set}" = set; t - # Check whether --with-sqlite3-libs or --without-sqlite3-libs was given. - if test "${with_sqlite3_libs+set}" = set; then - withval="$with_sqlite3_libs" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2506,9 +2506,9 @@ if test "${with_sqlite3_libs+set}" = set - LIBS="${LIBS} -L$withval" - SQLITE3LIB=$withval - SQLITE3LIBFOUND=1 -- -+ - fi -- -+ - - if test x"$SQLITE3LIB" != x""; then - echo $ac_n "checking your own SQLite3 client library""... $ac_c" 1>&6 -@@ -2536,7 +2536,7 @@ echo "configure:2527: checking default l - LIBS="${LIBS} -L/usr/local/lib" - echo "$ac_t""found in /usr/local/lib" 1>&6 - SQLITE3LIBFOUND=1 -- else -+ else - echo "$ac_t""not found" 1>&6 - fi - fi -@@ -2587,20 +2587,20 @@ EOF - - else - echo "$ac_t""no" 1>&6 --{ echo "configure: error: -+{ echo "configure: error: - ERROR: missing SQLite3 client library. Refer to: http://sqlite.org/ - " 1>&2; exit 1; } - fi - -- else -+ else - LIBS="${LIBS} -lsqlite3" -- fi -+ fi - - # Check whether --with-sqlite3-includes or --without-sqlite3-includes was given. - if test "${with_sqlite3_includes+set}" = set; then - withval="$with_sqlite3_includes" -- -- -+ -+ - absdir=`cd $withval 2>/dev/null && pwd` - if test x$absdir != x ; then - withval=$absdir -@@ -2609,7 +2609,7 @@ if test "${with_sqlite3_includes+set}" = - INCLUDES="${INCLUDES} -I$withval" - SQLITE3INCLUDES=$withval - SQLITE3INCLUDESFOUND=1 -- -+ - fi - - -@@ -2624,7 +2624,7 @@ echo "configure:2619: checking your own - fi - fi - -- if test x"$SQLITE3INCLUDESFOUND" = x""; then -+ if test x"$SQLITE3INCLUDESFOUND" = x""; then - echo $ac_n "checking default locations for sqlite3.h""... $ac_c" 1>&6 - echo "configure:2630: checking default locations for sqlite3.h" >&5 - if test -r /usr/include/sqlite3.h; then -@@ -2678,7 +2678,7 @@ else - echo "$ac_t""no" 1>&6 - { echo "configure: error: ERROR: missing SQLite3 headers" 1>&2; exit 1; } - fi -- -+ - fi - - cat >> confdefs.h <<\EOF -@@ -2690,7 +2690,7 @@ EOF - no) - echo "$ac_t""no" 1>&6 - ;; -- esac -+ esac - else - echo "$ac_t""no" 1>&6 - fi -@@ -2746,12 +2746,12 @@ fi - - if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then - echo "$ac_t""yes" 1>&6 -- USING_DLOPEN="yes" -+ USING_DLOPEN="yes" - else - echo "$ac_t""no" 1>&6 - fi -- -- if test x"$USING_DLOPEN" != x"yes"; then -+ -+ if test x"$USING_DLOPEN" != x"yes"; then - echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 - echo "configure:2757: checking for dlopen in -ldl" >&5 - ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` -@@ -2788,17 +2788,17 @@ fi - if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - USING_DLOPEN="yes" -- LIBS="${LIBS} -ldl" -+ LIBS="${LIBS} -ldl" - else - echo "$ac_t""no" 1>&6 -- { echo "configure: error: Unable to find dlopen(). Try with --disable-so" 1>&2; exit 1; } -+ { echo "configure: error: Unable to find dlopen(). Try with --disable-so" 1>&2; exit 1; } - fi -- -+ - fi - else - echo "$ac_t""yes" 1>&6 - fi -- -+ - else - echo "$ac_t""no" 1>&6 - echo $ac_n "checking for dlopen""... $ac_c" 1>&6 -@@ -2844,7 +2844,7 @@ fi - - if eval "test \"`echo '$ac_cv_func_'dlopen`\" = yes"; then - echo "$ac_t""yes" 1>&6 -- USING_DLOPEN="yes" -+ USING_DLOPEN="yes" - else - echo "$ac_t""no" 1>&6 - fi -@@ -2886,10 +2886,10 @@ fi - if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - USING_DLOPEN="yes" -- LIBS="${LIBS} -ldl" -+ LIBS="${LIBS} -ldl" - else - echo "$ac_t""no" 1>&6 -- { echo "configure: error: Unable to find dlopen(). Try with --disable-so" 1>&2; exit 1; } -+ { echo "configure: error: Unable to find dlopen(). Try with --disable-so" 1>&2; exit 1; } - fi - - fi -@@ -2906,7 +2906,7 @@ fi - - if test x"$USING_SQL" = x"yes"; then - PLUGINS="${PLUGINS} sql_common.c sql_handlers.c log_templates.c preprocess.c" -- LIBS="${LIBS} -lm -lz" -+ LIBS="${LIBS}" - fi - - echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -@@ -3089,7 +3089,7 @@ if eval "test \"`echo '$ac_cv_header_'$a - cat >> confdefs.h <&6 - fi -@@ -3114,12 +3114,12 @@ int x = sizeof(u_int64_t); x = x; - EOF - if { (eval echo configure:3116: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3131,7 +3131,7 @@ rm -f conftest* - EOF - - HAVE_U_INT64_T="1" -- -+ - fi - - fi -@@ -3154,12 +3154,12 @@ int x = sizeof(u_int32_t); x = x; - EOF - if { (eval echo configure:3156: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3171,7 +3171,7 @@ rm -f conftest* - EOF - - HAVE_U_INT32_T="1" -- -+ - fi - - fi -@@ -3194,12 +3194,12 @@ int x = sizeof(u_int16_t); x = x; - EOF - if { (eval echo configure:3196: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3211,7 +3211,7 @@ rm -f conftest* - EOF - - HAVE_U_INT16_T="1" -- -+ - fi - - fi -@@ -3234,12 +3234,12 @@ int x = sizeof(u_int8_t); x = x; - EOF - if { (eval echo configure:3236: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3251,7 +3251,7 @@ rm -f conftest* - EOF - - HAVE_U_INT8_T="1" -- -+ - fi - - fi -@@ -3274,12 +3274,12 @@ int x = sizeof(uint64_t); x = x; - EOF - if { (eval echo configure:3276: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3291,7 +3291,7 @@ rm -f conftest* - EOF - - HAVE_UINT64_T="1" -- -+ - fi - - fi -@@ -3314,12 +3314,12 @@ int x = sizeof(uint32_t); x = x; - EOF - if { (eval echo configure:3316: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3331,7 +3331,7 @@ rm -f conftest* - EOF - - HAVE_UINT32_T="1" -- -+ - fi - - fi -@@ -3354,12 +3354,12 @@ int x = sizeof(uint16_t); x = x; - EOF - if { (eval echo configure:3356: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3371,7 +3371,7 @@ rm -f conftest* - EOF - - HAVE_UINT16_T="1" -- -+ - fi - - fi -@@ -3394,12 +3394,12 @@ int x = sizeof(uint8_t); x = x; - EOF - if { (eval echo configure:3396: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=yes" -+ eval "ac_cv_type_$ac_lib_var=yes" - else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* -- eval "ac_cv_type_$ac_lib_var=no" -+ eval "ac_cv_type_$ac_lib_var=no" - fi - rm -f conftest* - if test `eval echo '$ac_cv_type_'$ac_lib_var` = "no" ; then -@@ -3411,7 +3411,7 @@ rm -f conftest* - EOF - - HAVE_UINT8_T="1" -- -+ - fi - - fi -@@ -3431,7 +3431,7 @@ EOF - else - echo "$ac_t""no" 1>&6 - fi -- -+ - else - echo "$ac_t""no" 1>&6 - -@@ -3449,8 +3449,8 @@ if test "${enable_threads+set}" = set; t - #define ENABLE_THREADS 1 - EOF - -- -- -+ -+ - case "$host" in - *-linux-*) - cat >> confdefs.h <<\EOF -@@ -3463,7 +3463,7 @@ EOF - - ;; - esac -- -+ - - - LIBS="${LIBS} -lpthread" -@@ -3472,7 +3472,7 @@ EOF - echo "$ac_t""no" 1>&6 - THREADS_SOURCES="" - fi -- -+ - else - echo "$ac_t""no" 1>&6 - -@@ -3490,7 +3490,7 @@ if test "${enable_ulog+set}" = set; then - else - echo "$ac_t""no" 1>&6 - fi -- -+ - else - echo "$ac_t""no" 1>&6 - -@@ -3588,7 +3588,7 @@ if eval "test \"`echo '$ac_cv_func_'$ac_ - cat >> confdefs.h <&6 - fi -@@ -3741,7 +3741,7 @@ ac_given_INSTALL="$INSTALL" - - trap 'rm -fr `echo " Makefile \ - src/Makefile src/nfprobe_plugin/Makefile \ -- src/sfprobe_plugin/Makefile -+ src/sfprobe_plugin/Makefile - src/bgp/Makefile " | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 - EOF - cat >> $CONFIG_STATUS <> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF ---- /dev/null -+++ pmacct-0.12.1/config.guess -@@ -0,0 +1,1502 @@ -+#! /bin/sh -+# Attempt to guess a canonical system name. -+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -+# Free Software Foundation, Inc. -+ -+timestamp='2009-12-30' -+ -+# This file is free software; you can redistribute it and/or modify it -+# under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, but -+# WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+# General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -+# 02110-1301, USA. -+# -+# As a special exception to the GNU General Public License, if you -+# distribute this file as part of a program that contains a -+# configuration script generated by Autoconf, you may include it under -+# the same distribution terms that you use for the rest of that program. -+ -+ -+# Originally written by Per Bothner. Please send patches (context -+# diff format) to and include a ChangeLog -+# entry. -+# -+# This script attempts to guess a canonical system name similar to -+# config.sub. If it succeeds, it prints the system name on stdout, and -+# exits with 0. Otherwise, it exits with 1. -+# -+# You can get the latest version of this script from: -+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD -+ -+me=`echo "$0" | sed -e 's,.*/,,'` -+ -+usage="\ -+Usage: $0 [OPTION] -+ -+Output the configuration name of the system \`$me' is run on. -+ -+Operation modes: -+ -h, --help print this help, then exit -+ -t, --time-stamp print date of last modification, then exit -+ -v, --version print version number, then exit -+ -+Report bugs and patches to ." -+ -+version="\ -+GNU config.guess ($timestamp) -+ -+Originally written by Per Bothner. -+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free -+Software Foundation, Inc. -+ -+This is free software; see the source for copying conditions. There is NO -+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -+ -+help=" -+Try \`$me --help' for more information." -+ -+# Parse command line -+while test $# -gt 0 ; do -+ case $1 in -+ --time-stamp | --time* | -t ) -+ echo "$timestamp" ; exit ;; -+ --version | -v ) -+ echo "$version" ; exit ;; -+ --help | --h* | -h ) -+ echo "$usage"; exit ;; -+ -- ) # Stop option processing -+ shift; break ;; -+ - ) # Use stdin as input. -+ break ;; -+ -* ) -+ echo "$me: invalid option $1$help" >&2 -+ exit 1 ;; -+ * ) -+ break ;; -+ esac -+done -+ -+if test $# != 0; then -+ echo "$me: too many arguments$help" >&2 -+ exit 1 -+fi -+ -+trap 'exit 1' 1 2 15 -+ -+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -+# compiler to aid in system detection is discouraged as it requires -+# temporary files to be created and, as you can see below, it is a -+# headache to deal with in a portable fashion. -+ -+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -+# use `HOST_CC' if defined, but it is deprecated. -+ -+# Portable tmp directory creation inspired by the Autoconf team. -+ -+set_cc_for_build=' -+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -+: ${TMPDIR=/tmp} ; -+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || -+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || -+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || -+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -+dummy=$tmp/dummy ; -+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -+case $CC_FOR_BUILD,$HOST_CC,$CC in -+ ,,) echo "int x;" > $dummy.c ; -+ for c in cc gcc c89 c99 ; do -+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then -+ CC_FOR_BUILD="$c"; break ; -+ fi ; -+ done ; -+ if test x"$CC_FOR_BUILD" = x ; then -+ CC_FOR_BUILD=no_compiler_found ; -+ fi -+ ;; -+ ,,*) CC_FOR_BUILD=$CC ;; -+ ,*,*) CC_FOR_BUILD=$HOST_CC ;; -+esac ; set_cc_for_build= ;' -+ -+# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -+# (ghazi@noc.rutgers.edu 1994-08-24) -+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then -+ PATH=$PATH:/.attbin ; export PATH -+fi -+ -+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -+ -+# Note: order is significant - the case branches are not exclusive. -+ -+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in -+ *:NetBSD:*:*) -+ # NetBSD (nbsd) targets should (where applicable) match one or -+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, -+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently -+ # switched to ELF, *-*-netbsd* would select the old -+ # object file format. This provides both forward -+ # compatibility and a consistent mechanism for selecting the -+ # object file format. -+ # -+ # Note: NetBSD doesn't particularly care about the vendor -+ # portion of the name. We always set it to "unknown". -+ sysctl="sysctl -n hw.machine_arch" -+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ -+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` -+ case "${UNAME_MACHINE_ARCH}" in -+ armeb) machine=armeb-unknown ;; -+ arm*) machine=arm-unknown ;; -+ sh3el) machine=shl-unknown ;; -+ sh3eb) machine=sh-unknown ;; -+ sh5el) machine=sh5le-unknown ;; -+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;; -+ esac -+ # The Operating System including object format, if it has switched -+ # to ELF recently, or will in the future. -+ case "${UNAME_MACHINE_ARCH}" in -+ arm*|i386|m68k|ns32k|sh3*|sparc|vax) -+ eval $set_cc_for_build -+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ -+ | grep -q __ELF__ -+ then -+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). -+ # Return netbsd for either. FIX? -+ os=netbsd -+ else -+ os=netbsdelf -+ fi -+ ;; -+ *) -+ os=netbsd -+ ;; -+ esac -+ # The OS release -+ # Debian GNU/NetBSD machines have a different userland, and -+ # thus, need a distinct triplet. However, they do not need -+ # kernel version information, so it can be replaced with a -+ # suitable tag, in the style of linux-gnu. -+ case "${UNAME_VERSION}" in -+ Debian*) -+ release='-gnu' -+ ;; -+ *) -+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` -+ ;; -+ esac -+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: -+ # contains redundant information, the shorter form: -+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. -+ echo "${machine}-${os}${release}" -+ exit ;; -+ *:OpenBSD:*:*) -+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` -+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} -+ exit ;; -+ *:ekkoBSD:*:*) -+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} -+ exit ;; -+ *:SolidBSD:*:*) -+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} -+ exit ;; -+ macppc:MirBSD:*:*) -+ echo powerpc-unknown-mirbsd${UNAME_RELEASE} -+ exit ;; -+ *:MirBSD:*:*) -+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} -+ exit ;; -+ alpha:OSF1:*:*) -+ case $UNAME_RELEASE in -+ *4.0) -+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` -+ ;; -+ *5.*) -+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` -+ ;; -+ esac -+ # According to Compaq, /usr/sbin/psrinfo has been available on -+ # OSF/1 and Tru64 systems produced since 1995. I hope that -+ # covers most systems running today. This code pipes the CPU -+ # types through head -n 1, so we only detect the type of CPU 0. -+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` -+ case "$ALPHA_CPU_TYPE" in -+ "EV4 (21064)") -+ UNAME_MACHINE="alpha" ;; -+ "EV4.5 (21064)") -+ UNAME_MACHINE="alpha" ;; -+ "LCA4 (21066/21068)") -+ UNAME_MACHINE="alpha" ;; -+ "EV5 (21164)") -+ UNAME_MACHINE="alphaev5" ;; -+ "EV5.6 (21164A)") -+ UNAME_MACHINE="alphaev56" ;; -+ "EV5.6 (21164PC)") -+ UNAME_MACHINE="alphapca56" ;; -+ "EV5.7 (21164PC)") -+ UNAME_MACHINE="alphapca57" ;; -+ "EV6 (21264)") -+ UNAME_MACHINE="alphaev6" ;; -+ "EV6.7 (21264A)") -+ UNAME_MACHINE="alphaev67" ;; -+ "EV6.8CB (21264C)") -+ UNAME_MACHINE="alphaev68" ;; -+ "EV6.8AL (21264B)") -+ UNAME_MACHINE="alphaev68" ;; -+ "EV6.8CX (21264D)") -+ UNAME_MACHINE="alphaev68" ;; -+ "EV6.9A (21264/EV69A)") -+ UNAME_MACHINE="alphaev69" ;; -+ "EV7 (21364)") -+ UNAME_MACHINE="alphaev7" ;; -+ "EV7.9 (21364A)") -+ UNAME_MACHINE="alphaev79" ;; -+ esac -+ # A Pn.n version is a patched version. -+ # A Vn.n version is a released version. -+ # A Tn.n version is a released field test version. -+ # A Xn.n version is an unreleased experimental baselevel. -+ # 1.2 uses "1.2" for uname -r. -+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` -+ exit ;; -+ Alpha\ *:Windows_NT*:*) -+ # How do we know it's Interix rather than the generic POSIX subsystem? -+ # Should we change UNAME_MACHINE based on the output of uname instead -+ # of the specific Alpha model? -+ echo alpha-pc-interix -+ exit ;; -+ 21064:Windows_NT:50:3) -+ echo alpha-dec-winnt3.5 -+ exit ;; -+ Amiga*:UNIX_System_V:4.0:*) -+ echo m68k-unknown-sysv4 -+ exit ;; -+ *:[Aa]miga[Oo][Ss]:*:*) -+ echo ${UNAME_MACHINE}-unknown-amigaos -+ exit ;; -+ *:[Mm]orph[Oo][Ss]:*:*) -+ echo ${UNAME_MACHINE}-unknown-morphos -+ exit ;; -+ *:OS/390:*:*) -+ echo i370-ibm-openedition -+ exit ;; -+ *:z/VM:*:*) -+ echo s390-ibm-zvmoe -+ exit ;; -+ *:OS400:*:*) -+ echo powerpc-ibm-os400 -+ exit ;; -+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) -+ echo arm-acorn-riscix${UNAME_RELEASE} -+ exit ;; -+ arm:riscos:*:*|arm:RISCOS:*:*) -+ echo arm-unknown-riscos -+ exit ;; -+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) -+ echo hppa1.1-hitachi-hiuxmpp -+ exit ;; -+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) -+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. -+ if test "`(/bin/universe) 2>/dev/null`" = att ; then -+ echo pyramid-pyramid-sysv3 -+ else -+ echo pyramid-pyramid-bsd -+ fi -+ exit ;; -+ NILE*:*:*:dcosx) -+ echo pyramid-pyramid-svr4 -+ exit ;; -+ DRS?6000:unix:4.0:6*) -+ echo sparc-icl-nx6 -+ exit ;; -+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) -+ case `/usr/bin/uname -p` in -+ sparc) echo sparc-icl-nx7; exit ;; -+ esac ;; -+ s390x:SunOS:*:*) -+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ sun4H:SunOS:5.*:*) -+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) -+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) -+ echo i386-pc-auroraux${UNAME_RELEASE} -+ exit ;; -+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) -+ eval $set_cc_for_build -+ SUN_ARCH="i386" -+ # If there is a compiler, see if it is configured for 64-bit objects. -+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. -+ # This test works for both compilers. -+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then -+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ -+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ -+ grep IS_64BIT_ARCH >/dev/null -+ then -+ SUN_ARCH="x86_64" -+ fi -+ fi -+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ sun4*:SunOS:6*:*) -+ # According to config.sub, this is the proper way to canonicalize -+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but -+ # it's likely to be more like Solaris than SunOS4. -+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ sun4*:SunOS:*:*) -+ case "`/usr/bin/arch -k`" in -+ Series*|S4*) -+ UNAME_RELEASE=`uname -v` -+ ;; -+ esac -+ # Japanese Language versions have a version number like `4.1.3-JL'. -+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` -+ exit ;; -+ sun3*:SunOS:*:*) -+ echo m68k-sun-sunos${UNAME_RELEASE} -+ exit ;; -+ sun*:*:4.2BSD:*) -+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` -+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 -+ case "`/bin/arch`" in -+ sun3) -+ echo m68k-sun-sunos${UNAME_RELEASE} -+ ;; -+ sun4) -+ echo sparc-sun-sunos${UNAME_RELEASE} -+ ;; -+ esac -+ exit ;; -+ aushp:SunOS:*:*) -+ echo sparc-auspex-sunos${UNAME_RELEASE} -+ exit ;; -+ # The situation for MiNT is a little confusing. The machine name -+ # can be virtually everything (everything which is not -+ # "atarist" or "atariste" at least should have a processor -+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT" -+ # to the lowercase version "mint" (or "freemint"). Finally -+ # the system name "TOS" denotes a system which is actually not -+ # MiNT. But MiNT is downward compatible to TOS, so this should -+ # be no problem. -+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) -+ echo m68k-atari-mint${UNAME_RELEASE} -+ exit ;; -+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) -+ echo m68k-atari-mint${UNAME_RELEASE} -+ exit ;; -+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) -+ echo m68k-atari-mint${UNAME_RELEASE} -+ exit ;; -+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) -+ echo m68k-milan-mint${UNAME_RELEASE} -+ exit ;; -+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) -+ echo m68k-hades-mint${UNAME_RELEASE} -+ exit ;; -+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) -+ echo m68k-unknown-mint${UNAME_RELEASE} -+ exit ;; -+ m68k:machten:*:*) -+ echo m68k-apple-machten${UNAME_RELEASE} -+ exit ;; -+ powerpc:machten:*:*) -+ echo powerpc-apple-machten${UNAME_RELEASE} -+ exit ;; -+ RISC*:Mach:*:*) -+ echo mips-dec-mach_bsd4.3 -+ exit ;; -+ RISC*:ULTRIX:*:*) -+ echo mips-dec-ultrix${UNAME_RELEASE} -+ exit ;; -+ VAX*:ULTRIX*:*:*) -+ echo vax-dec-ultrix${UNAME_RELEASE} -+ exit ;; -+ 2020:CLIX:*:* | 2430:CLIX:*:*) -+ echo clipper-intergraph-clix${UNAME_RELEASE} -+ exit ;; -+ mips:*:*:UMIPS | mips:*:*:RISCos) -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+#ifdef __cplusplus -+#include /* for printf() prototype */ -+ int main (int argc, char *argv[]) { -+#else -+ int main (argc, argv) int argc; char *argv[]; { -+#endif -+ #if defined (host_mips) && defined (MIPSEB) -+ #if defined (SYSTYPE_SYSV) -+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); -+ #endif -+ #if defined (SYSTYPE_SVR4) -+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); -+ #endif -+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) -+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); -+ #endif -+ #endif -+ exit (-1); -+ } -+EOF -+ $CC_FOR_BUILD -o $dummy $dummy.c && -+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && -+ SYSTEM_NAME=`$dummy $dummyarg` && -+ { echo "$SYSTEM_NAME"; exit; } -+ echo mips-mips-riscos${UNAME_RELEASE} -+ exit ;; -+ Motorola:PowerMAX_OS:*:*) -+ echo powerpc-motorola-powermax -+ exit ;; -+ Motorola:*:4.3:PL8-*) -+ echo powerpc-harris-powermax -+ exit ;; -+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) -+ echo powerpc-harris-powermax -+ exit ;; -+ Night_Hawk:Power_UNIX:*:*) -+ echo powerpc-harris-powerunix -+ exit ;; -+ m88k:CX/UX:7*:*) -+ echo m88k-harris-cxux7 -+ exit ;; -+ m88k:*:4*:R4*) -+ echo m88k-motorola-sysv4 -+ exit ;; -+ m88k:*:3*:R3*) -+ echo m88k-motorola-sysv3 -+ exit ;; -+ AViiON:dgux:*:*) -+ # DG/UX returns AViiON for all architectures -+ UNAME_PROCESSOR=`/usr/bin/uname -p` -+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] -+ then -+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ -+ [ ${TARGET_BINARY_INTERFACE}x = x ] -+ then -+ echo m88k-dg-dgux${UNAME_RELEASE} -+ else -+ echo m88k-dg-dguxbcs${UNAME_RELEASE} -+ fi -+ else -+ echo i586-dg-dgux${UNAME_RELEASE} -+ fi -+ exit ;; -+ M88*:DolphinOS:*:*) # DolphinOS (SVR3) -+ echo m88k-dolphin-sysv3 -+ exit ;; -+ M88*:*:R3*:*) -+ # Delta 88k system running SVR3 -+ echo m88k-motorola-sysv3 -+ exit ;; -+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) -+ echo m88k-tektronix-sysv3 -+ exit ;; -+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) -+ echo m68k-tektronix-bsd -+ exit ;; -+ *:IRIX*:*:*) -+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` -+ exit ;; -+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. -+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id -+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' -+ i*86:AIX:*:*) -+ echo i386-ibm-aix -+ exit ;; -+ ia64:AIX:*:*) -+ if [ -x /usr/bin/oslevel ] ; then -+ IBM_REV=`/usr/bin/oslevel` -+ else -+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} -+ fi -+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} -+ exit ;; -+ *:AIX:2:3) -+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+ #include -+ -+ main() -+ { -+ if (!__power_pc()) -+ exit(1); -+ puts("powerpc-ibm-aix3.2.5"); -+ exit(0); -+ } -+EOF -+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` -+ then -+ echo "$SYSTEM_NAME" -+ else -+ echo rs6000-ibm-aix3.2.5 -+ fi -+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then -+ echo rs6000-ibm-aix3.2.4 -+ else -+ echo rs6000-ibm-aix3.2 -+ fi -+ exit ;; -+ *:AIX:*:[456]) -+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` -+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then -+ IBM_ARCH=rs6000 -+ else -+ IBM_ARCH=powerpc -+ fi -+ if [ -x /usr/bin/oslevel ] ; then -+ IBM_REV=`/usr/bin/oslevel` -+ else -+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} -+ fi -+ echo ${IBM_ARCH}-ibm-aix${IBM_REV} -+ exit ;; -+ *:AIX:*:*) -+ echo rs6000-ibm-aix -+ exit ;; -+ ibmrt:4.4BSD:*|romp-ibm:BSD:*) -+ echo romp-ibm-bsd4.4 -+ exit ;; -+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and -+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to -+ exit ;; # report: romp-ibm BSD 4.3 -+ *:BOSX:*:*) -+ echo rs6000-bull-bosx -+ exit ;; -+ DPX/2?00:B.O.S.:*:*) -+ echo m68k-bull-sysv3 -+ exit ;; -+ 9000/[34]??:4.3bsd:1.*:*) -+ echo m68k-hp-bsd -+ exit ;; -+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) -+ echo m68k-hp-bsd4.4 -+ exit ;; -+ 9000/[34678]??:HP-UX:*:*) -+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` -+ case "${UNAME_MACHINE}" in -+ 9000/31? ) HP_ARCH=m68000 ;; -+ 9000/[34]?? ) HP_ARCH=m68k ;; -+ 9000/[678][0-9][0-9]) -+ if [ -x /usr/bin/getconf ]; then -+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` -+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` -+ case "${sc_cpu_version}" in -+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 -+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 -+ 532) # CPU_PA_RISC2_0 -+ case "${sc_kernel_bits}" in -+ 32) HP_ARCH="hppa2.0n" ;; -+ 64) HP_ARCH="hppa2.0w" ;; -+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 -+ esac ;; -+ esac -+ fi -+ if [ "${HP_ARCH}" = "" ]; then -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+ -+ #define _HPUX_SOURCE -+ #include -+ #include -+ -+ int main () -+ { -+ #if defined(_SC_KERNEL_BITS) -+ long bits = sysconf(_SC_KERNEL_BITS); -+ #endif -+ long cpu = sysconf (_SC_CPU_VERSION); -+ -+ switch (cpu) -+ { -+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break; -+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break; -+ case CPU_PA_RISC2_0: -+ #if defined(_SC_KERNEL_BITS) -+ switch (bits) -+ { -+ case 64: puts ("hppa2.0w"); break; -+ case 32: puts ("hppa2.0n"); break; -+ default: puts ("hppa2.0"); break; -+ } break; -+ #else /* !defined(_SC_KERNEL_BITS) */ -+ puts ("hppa2.0"); break; -+ #endif -+ default: puts ("hppa1.0"); break; -+ } -+ exit (0); -+ } -+EOF -+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` -+ test -z "$HP_ARCH" && HP_ARCH=hppa -+ fi ;; -+ esac -+ if [ ${HP_ARCH} = "hppa2.0w" ] -+ then -+ eval $set_cc_for_build -+ -+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating -+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler -+ # generating 64-bit code. GNU and HP use different nomenclature: -+ # -+ # $ CC_FOR_BUILD=cc ./config.guess -+ # => hppa2.0w-hp-hpux11.23 -+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess -+ # => hppa64-hp-hpux11.23 -+ -+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | -+ grep -q __LP64__ -+ then -+ HP_ARCH="hppa2.0w" -+ else -+ HP_ARCH="hppa64" -+ fi -+ fi -+ echo ${HP_ARCH}-hp-hpux${HPUX_REV} -+ exit ;; -+ ia64:HP-UX:*:*) -+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` -+ echo ia64-hp-hpux${HPUX_REV} -+ exit ;; -+ 3050*:HI-UX:*:*) -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+ #include -+ int -+ main () -+ { -+ long cpu = sysconf (_SC_CPU_VERSION); -+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns -+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct -+ results, however. */ -+ if (CPU_IS_PA_RISC (cpu)) -+ { -+ switch (cpu) -+ { -+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; -+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; -+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; -+ default: puts ("hppa-hitachi-hiuxwe2"); break; -+ } -+ } -+ else if (CPU_IS_HP_MC68K (cpu)) -+ puts ("m68k-hitachi-hiuxwe2"); -+ else puts ("unknown-hitachi-hiuxwe2"); -+ exit (0); -+ } -+EOF -+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && -+ { echo "$SYSTEM_NAME"; exit; } -+ echo unknown-hitachi-hiuxwe2 -+ exit ;; -+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) -+ echo hppa1.1-hp-bsd -+ exit ;; -+ 9000/8??:4.3bsd:*:*) -+ echo hppa1.0-hp-bsd -+ exit ;; -+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) -+ echo hppa1.0-hp-mpeix -+ exit ;; -+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) -+ echo hppa1.1-hp-osf -+ exit ;; -+ hp8??:OSF1:*:*) -+ echo hppa1.0-hp-osf -+ exit ;; -+ i*86:OSF1:*:*) -+ if [ -x /usr/sbin/sysversion ] ; then -+ echo ${UNAME_MACHINE}-unknown-osf1mk -+ else -+ echo ${UNAME_MACHINE}-unknown-osf1 -+ fi -+ exit ;; -+ parisc*:Lites*:*:*) -+ echo hppa1.1-hp-lites -+ exit ;; -+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) -+ echo c1-convex-bsd -+ exit ;; -+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) -+ if getsysinfo -f scalar_acc -+ then echo c32-convex-bsd -+ else echo c2-convex-bsd -+ fi -+ exit ;; -+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) -+ echo c34-convex-bsd -+ exit ;; -+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) -+ echo c38-convex-bsd -+ exit ;; -+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) -+ echo c4-convex-bsd -+ exit ;; -+ CRAY*Y-MP:*:*:*) -+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' -+ exit ;; -+ CRAY*[A-Z]90:*:*:*) -+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ -+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -+ -e 's/\.[^.]*$/.X/' -+ exit ;; -+ CRAY*TS:*:*:*) -+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' -+ exit ;; -+ CRAY*T3E:*:*:*) -+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' -+ exit ;; -+ CRAY*SV1:*:*:*) -+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' -+ exit ;; -+ *:UNICOS/mp:*:*) -+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' -+ exit ;; -+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) -+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` -+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` -+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" -+ exit ;; -+ 5000:UNIX_System_V:4.*:*) -+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` -+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` -+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" -+ exit ;; -+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) -+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} -+ exit ;; -+ sparc*:BSD/OS:*:*) -+ echo sparc-unknown-bsdi${UNAME_RELEASE} -+ exit ;; -+ *:BSD/OS:*:*) -+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} -+ exit ;; -+ *:FreeBSD:*:*) -+ case ${UNAME_MACHINE} in -+ pc98) -+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; -+ amd64) -+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; -+ *) -+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; -+ esac -+ exit ;; -+ i*:CYGWIN*:*) -+ echo ${UNAME_MACHINE}-pc-cygwin -+ exit ;; -+ *:MINGW*:*) -+ echo ${UNAME_MACHINE}-pc-mingw32 -+ exit ;; -+ i*:windows32*:*) -+ # uname -m includes "-pc" on this system. -+ echo ${UNAME_MACHINE}-mingw32 -+ exit ;; -+ i*:PW*:*) -+ echo ${UNAME_MACHINE}-pc-pw32 -+ exit ;; -+ *:Interix*:*) -+ case ${UNAME_MACHINE} in -+ x86) -+ echo i586-pc-interix${UNAME_RELEASE} -+ exit ;; -+ authenticamd | genuineintel | EM64T) -+ echo x86_64-unknown-interix${UNAME_RELEASE} -+ exit ;; -+ IA64) -+ echo ia64-unknown-interix${UNAME_RELEASE} -+ exit ;; -+ esac ;; -+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) -+ echo i${UNAME_MACHINE}-pc-mks -+ exit ;; -+ 8664:Windows_NT:*) -+ echo x86_64-pc-mks -+ exit ;; -+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*) -+ # How do we know it's Interix rather than the generic POSIX subsystem? -+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we -+ # UNAME_MACHINE based on the output of uname instead of i386? -+ echo i586-pc-interix -+ exit ;; -+ i*:UWIN*:*) -+ echo ${UNAME_MACHINE}-pc-uwin -+ exit ;; -+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) -+ echo x86_64-unknown-cygwin -+ exit ;; -+ p*:CYGWIN*:*) -+ echo powerpcle-unknown-cygwin -+ exit ;; -+ prep*:SunOS:5.*:*) -+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` -+ exit ;; -+ *:GNU:*:*) -+ # the GNU system -+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` -+ exit ;; -+ *:GNU/*:*:*) -+ # other systems with GNU libc and userland -+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu -+ exit ;; -+ i*86:Minix:*:*) -+ echo ${UNAME_MACHINE}-pc-minix -+ exit ;; -+ alpha:Linux:*:*) -+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in -+ EV5) UNAME_MACHINE=alphaev5 ;; -+ EV56) UNAME_MACHINE=alphaev56 ;; -+ PCA56) UNAME_MACHINE=alphapca56 ;; -+ PCA57) UNAME_MACHINE=alphapca56 ;; -+ EV6) UNAME_MACHINE=alphaev6 ;; -+ EV67) UNAME_MACHINE=alphaev67 ;; -+ EV68*) UNAME_MACHINE=alphaev68 ;; -+ esac -+ objdump --private-headers /bin/sh | grep -q ld.so.1 -+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi -+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} -+ exit ;; -+ arm*:Linux:*:*) -+ eval $set_cc_for_build -+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ -+ | grep -q __ARM_EABI__ -+ then -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ else -+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi -+ fi -+ exit ;; -+ avr32*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ cris:Linux:*:*) -+ echo cris-axis-linux-gnu -+ exit ;; -+ crisv32:Linux:*:*) -+ echo crisv32-axis-linux-gnu -+ exit ;; -+ frv:Linux:*:*) -+ echo frv-unknown-linux-gnu -+ exit ;; -+ i*86:Linux:*:*) -+ LIBC=gnu -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+ #ifdef __dietlibc__ -+ LIBC=dietlibc -+ #endif -+EOF -+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` -+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}" -+ exit ;; -+ ia64:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ m32r*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ m68*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ mips:Linux:*:* | mips64:Linux:*:*) -+ eval $set_cc_for_build -+ sed 's/^ //' << EOF >$dummy.c -+ #undef CPU -+ #undef ${UNAME_MACHINE} -+ #undef ${UNAME_MACHINE}el -+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) -+ CPU=${UNAME_MACHINE}el -+ #else -+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) -+ CPU=${UNAME_MACHINE} -+ #else -+ CPU= -+ #endif -+ #endif -+EOF -+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` -+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } -+ ;; -+ or32:Linux:*:*) -+ echo or32-unknown-linux-gnu -+ exit ;; -+ padre:Linux:*:*) -+ echo sparc-unknown-linux-gnu -+ exit ;; -+ parisc64:Linux:*:* | hppa64:Linux:*:*) -+ echo hppa64-unknown-linux-gnu -+ exit ;; -+ parisc:Linux:*:* | hppa:Linux:*:*) -+ # Look for CPU level -+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in -+ PA7*) echo hppa1.1-unknown-linux-gnu ;; -+ PA8*) echo hppa2.0-unknown-linux-gnu ;; -+ *) echo hppa-unknown-linux-gnu ;; -+ esac -+ exit ;; -+ ppc64:Linux:*:*) -+ echo powerpc64-unknown-linux-gnu -+ exit ;; -+ ppc:Linux:*:*) -+ echo powerpc-unknown-linux-gnu -+ exit ;; -+ s390:Linux:*:* | s390x:Linux:*:*) -+ echo ${UNAME_MACHINE}-ibm-linux -+ exit ;; -+ sh64*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ sh*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ sparc:Linux:*:* | sparc64:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ vax:Linux:*:*) -+ echo ${UNAME_MACHINE}-dec-linux-gnu -+ exit ;; -+ x86_64:Linux:*:*) -+ echo x86_64-unknown-linux-gnu -+ exit ;; -+ xtensa*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux-gnu -+ exit ;; -+ i*86:DYNIX/ptx:4*:*) -+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. -+ # earlier versions are messed up and put the nodename in both -+ # sysname and nodename. -+ echo i386-sequent-sysv4 -+ exit ;; -+ i*86:UNIX_SV:4.2MP:2.*) -+ # Unixware is an offshoot of SVR4, but it has its own version -+ # number series starting with 2... -+ # I am not positive that other SVR4 systems won't match this, -+ # I just have to hope. -- rms. -+ # Use sysv4.2uw... so that sysv4* matches it. -+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} -+ exit ;; -+ i*86:OS/2:*:*) -+ # If we were able to find `uname', then EMX Unix compatibility -+ # is probably installed. -+ echo ${UNAME_MACHINE}-pc-os2-emx -+ exit ;; -+ i*86:XTS-300:*:STOP) -+ echo ${UNAME_MACHINE}-unknown-stop -+ exit ;; -+ i*86:atheos:*:*) -+ echo ${UNAME_MACHINE}-unknown-atheos -+ exit ;; -+ i*86:syllable:*:*) -+ echo ${UNAME_MACHINE}-pc-syllable -+ exit ;; -+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) -+ echo i386-unknown-lynxos${UNAME_RELEASE} -+ exit ;; -+ i*86:*DOS:*:*) -+ echo ${UNAME_MACHINE}-pc-msdosdjgpp -+ exit ;; -+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) -+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` -+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then -+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} -+ else -+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} -+ fi -+ exit ;; -+ i*86:*:5:[678]*) -+ # UnixWare 7.x, OpenUNIX and OpenServer 6. -+ case `/bin/uname -X | grep "^Machine"` in -+ *486*) UNAME_MACHINE=i486 ;; -+ *Pentium) UNAME_MACHINE=i586 ;; -+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;; -+ esac -+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} -+ exit ;; -+ i*86:*:3.2:*) -+ if test -f /usr/options/cb.name; then -+ UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then -+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` -+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 -+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ -+ && UNAME_MACHINE=i586 -+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ -+ && UNAME_MACHINE=i686 -+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ -+ && UNAME_MACHINE=i686 -+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL -+ else -+ echo ${UNAME_MACHINE}-pc-sysv32 -+ fi -+ exit ;; -+ pc:*:*:*) -+ # Left here for compatibility: -+ # uname -m prints for DJGPP always 'pc', but it prints nothing about -+ # the processor, so we play safe by assuming i586. -+ # Note: whatever this is, it MUST be the same as what config.sub -+ # prints for the "djgpp" host, or else GDB configury will decide that -+ # this is a cross-build. -+ echo i586-pc-msdosdjgpp -+ exit ;; -+ Intel:Mach:3*:*) -+ echo i386-pc-mach3 -+ exit ;; -+ paragon:*:*:*) -+ echo i860-intel-osf1 -+ exit ;; -+ i860:*:4.*:*) # i860-SVR4 -+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then -+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 -+ else # Add other i860-SVR4 vendors below as they are discovered. -+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 -+ fi -+ exit ;; -+ mini*:CTIX:SYS*5:*) -+ # "miniframe" -+ echo m68010-convergent-sysv -+ exit ;; -+ mc68k:UNIX:SYSTEM5:3.51m) -+ echo m68k-convergent-sysv -+ exit ;; -+ M680?0:D-NIX:5.3:*) -+ echo m68k-diab-dnix -+ exit ;; -+ M68*:*:R3V[5678]*:*) -+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; -+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) -+ OS_REL='' -+ test -r /etc/.relid \ -+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` -+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ -+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } -+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ -+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; -+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) -+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ -+ && { echo i486-ncr-sysv4; exit; } ;; -+ NCR*:*:4.2:* | MPRAS*:*:4.2:*) -+ OS_REL='.3' -+ test -r /etc/.relid \ -+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` -+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ -+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } -+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ -+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } -+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ -+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; -+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) -+ echo m68k-unknown-lynxos${UNAME_RELEASE} -+ exit ;; -+ mc68030:UNIX_System_V:4.*:*) -+ echo m68k-atari-sysv4 -+ exit ;; -+ TSUNAMI:LynxOS:2.*:*) -+ echo sparc-unknown-lynxos${UNAME_RELEASE} -+ exit ;; -+ rs6000:LynxOS:2.*:*) -+ echo rs6000-unknown-lynxos${UNAME_RELEASE} -+ exit ;; -+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) -+ echo powerpc-unknown-lynxos${UNAME_RELEASE} -+ exit ;; -+ SM[BE]S:UNIX_SV:*:*) -+ echo mips-dde-sysv${UNAME_RELEASE} -+ exit ;; -+ RM*:ReliantUNIX-*:*:*) -+ echo mips-sni-sysv4 -+ exit ;; -+ RM*:SINIX-*:*:*) -+ echo mips-sni-sysv4 -+ exit ;; -+ *:SINIX-*:*:*) -+ if uname -p 2>/dev/null >/dev/null ; then -+ UNAME_MACHINE=`(uname -p) 2>/dev/null` -+ echo ${UNAME_MACHINE}-sni-sysv4 -+ else -+ echo ns32k-sni-sysv -+ fi -+ exit ;; -+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort -+ # says -+ echo i586-unisys-sysv4 -+ exit ;; -+ *:UNIX_System_V:4*:FTX*) -+ # From Gerald Hewes . -+ # How about differentiating between stratus architectures? -djm -+ echo hppa1.1-stratus-sysv4 -+ exit ;; -+ *:*:*:FTX*) -+ # From seanf@swdc.stratus.com. -+ echo i860-stratus-sysv4 -+ exit ;; -+ i*86:VOS:*:*) -+ # From Paul.Green@stratus.com. -+ echo ${UNAME_MACHINE}-stratus-vos -+ exit ;; -+ *:VOS:*:*) -+ # From Paul.Green@stratus.com. -+ echo hppa1.1-stratus-vos -+ exit ;; -+ mc68*:A/UX:*:*) -+ echo m68k-apple-aux${UNAME_RELEASE} -+ exit ;; -+ news*:NEWS-OS:6*:*) -+ echo mips-sony-newsos6 -+ exit ;; -+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) -+ if [ -d /usr/nec ]; then -+ echo mips-nec-sysv${UNAME_RELEASE} -+ else -+ echo mips-unknown-sysv${UNAME_RELEASE} -+ fi -+ exit ;; -+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. -+ echo powerpc-be-beos -+ exit ;; -+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. -+ echo powerpc-apple-beos -+ exit ;; -+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible. -+ echo i586-pc-beos -+ exit ;; -+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible. -+ echo i586-pc-haiku -+ exit ;; -+ SX-4:SUPER-UX:*:*) -+ echo sx4-nec-superux${UNAME_RELEASE} -+ exit ;; -+ SX-5:SUPER-UX:*:*) -+ echo sx5-nec-superux${UNAME_RELEASE} -+ exit ;; -+ SX-6:SUPER-UX:*:*) -+ echo sx6-nec-superux${UNAME_RELEASE} -+ exit ;; -+ SX-7:SUPER-UX:*:*) -+ echo sx7-nec-superux${UNAME_RELEASE} -+ exit ;; -+ SX-8:SUPER-UX:*:*) -+ echo sx8-nec-superux${UNAME_RELEASE} -+ exit ;; -+ SX-8R:SUPER-UX:*:*) -+ echo sx8r-nec-superux${UNAME_RELEASE} -+ exit ;; -+ Power*:Rhapsody:*:*) -+ echo powerpc-apple-rhapsody${UNAME_RELEASE} -+ exit ;; -+ *:Rhapsody:*:*) -+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} -+ exit ;; -+ *:Darwin:*:*) -+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown -+ case $UNAME_PROCESSOR in -+ i386) -+ eval $set_cc_for_build -+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then -+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ -+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ -+ grep IS_64BIT_ARCH >/dev/null -+ then -+ UNAME_PROCESSOR="x86_64" -+ fi -+ fi ;; -+ unknown) UNAME_PROCESSOR=powerpc ;; -+ esac -+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} -+ exit ;; -+ *:procnto*:*:* | *:QNX:[0123456789]*:*) -+ UNAME_PROCESSOR=`uname -p` -+ if test "$UNAME_PROCESSOR" = "x86"; then -+ UNAME_PROCESSOR=i386 -+ UNAME_MACHINE=pc -+ fi -+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} -+ exit ;; -+ *:QNX:*:4*) -+ echo i386-pc-qnx -+ exit ;; -+ NSE-?:NONSTOP_KERNEL:*:*) -+ echo nse-tandem-nsk${UNAME_RELEASE} -+ exit ;; -+ NSR-?:NONSTOP_KERNEL:*:*) -+ echo nsr-tandem-nsk${UNAME_RELEASE} -+ exit ;; -+ *:NonStop-UX:*:*) -+ echo mips-compaq-nonstopux -+ exit ;; -+ BS2000:POSIX*:*:*) -+ echo bs2000-siemens-sysv -+ exit ;; -+ DS/*:UNIX_System_V:*:*) -+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} -+ exit ;; -+ *:Plan9:*:*) -+ # "uname -m" is not consistent, so use $cputype instead. 386 -+ # is converted to i386 for consistency with other x86 -+ # operating systems. -+ if test "$cputype" = "386"; then -+ UNAME_MACHINE=i386 -+ else -+ UNAME_MACHINE="$cputype" -+ fi -+ echo ${UNAME_MACHINE}-unknown-plan9 -+ exit ;; -+ *:TOPS-10:*:*) -+ echo pdp10-unknown-tops10 -+ exit ;; -+ *:TENEX:*:*) -+ echo pdp10-unknown-tenex -+ exit ;; -+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) -+ echo pdp10-dec-tops20 -+ exit ;; -+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) -+ echo pdp10-xkl-tops20 -+ exit ;; -+ *:TOPS-20:*:*) -+ echo pdp10-unknown-tops20 -+ exit ;; -+ *:ITS:*:*) -+ echo pdp10-unknown-its -+ exit ;; -+ SEI:*:*:SEIUX) -+ echo mips-sei-seiux${UNAME_RELEASE} -+ exit ;; -+ *:DragonFly:*:*) -+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` -+ exit ;; -+ *:*VMS:*:*) -+ UNAME_MACHINE=`(uname -p) 2>/dev/null` -+ case "${UNAME_MACHINE}" in -+ A*) echo alpha-dec-vms ; exit ;; -+ I*) echo ia64-dec-vms ; exit ;; -+ V*) echo vax-dec-vms ; exit ;; -+ esac ;; -+ *:XENIX:*:SysV) -+ echo i386-pc-xenix -+ exit ;; -+ i*86:skyos:*:*) -+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' -+ exit ;; -+ i*86:rdos:*:*) -+ echo ${UNAME_MACHINE}-pc-rdos -+ exit ;; -+ i*86:AROS:*:*) -+ echo ${UNAME_MACHINE}-pc-aros -+ exit ;; -+esac -+ -+#echo '(No uname command or uname output not recognized.)' 1>&2 -+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 -+ -+eval $set_cc_for_build -+cat >$dummy.c < -+# include -+#endif -+main () -+{ -+#if defined (sony) -+#if defined (MIPSEB) -+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, -+ I don't know.... */ -+ printf ("mips-sony-bsd\n"); exit (0); -+#else -+#include -+ printf ("m68k-sony-newsos%s\n", -+#ifdef NEWSOS4 -+ "4" -+#else -+ "" -+#endif -+ ); exit (0); -+#endif -+#endif -+ -+#if defined (__arm) && defined (__acorn) && defined (__unix) -+ printf ("arm-acorn-riscix\n"); exit (0); -+#endif -+ -+#if defined (hp300) && !defined (hpux) -+ printf ("m68k-hp-bsd\n"); exit (0); -+#endif -+ -+#if defined (NeXT) -+#if !defined (__ARCHITECTURE__) -+#define __ARCHITECTURE__ "m68k" -+#endif -+ int version; -+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; -+ if (version < 4) -+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); -+ else -+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); -+ exit (0); -+#endif -+ -+#if defined (MULTIMAX) || defined (n16) -+#if defined (UMAXV) -+ printf ("ns32k-encore-sysv\n"); exit (0); -+#else -+#if defined (CMU) -+ printf ("ns32k-encore-mach\n"); exit (0); -+#else -+ printf ("ns32k-encore-bsd\n"); exit (0); -+#endif -+#endif -+#endif -+ -+#if defined (__386BSD__) -+ printf ("i386-pc-bsd\n"); exit (0); -+#endif -+ -+#if defined (sequent) -+#if defined (i386) -+ printf ("i386-sequent-dynix\n"); exit (0); -+#endif -+#if defined (ns32000) -+ printf ("ns32k-sequent-dynix\n"); exit (0); -+#endif -+#endif -+ -+#if defined (_SEQUENT_) -+ struct utsname un; -+ -+ uname(&un); -+ -+ if (strncmp(un.version, "V2", 2) == 0) { -+ printf ("i386-sequent-ptx2\n"); exit (0); -+ } -+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ -+ printf ("i386-sequent-ptx1\n"); exit (0); -+ } -+ printf ("i386-sequent-ptx\n"); exit (0); -+ -+#endif -+ -+#if defined (vax) -+# if !defined (ultrix) -+# include -+# if defined (BSD) -+# if BSD == 43 -+ printf ("vax-dec-bsd4.3\n"); exit (0); -+# else -+# if BSD == 199006 -+ printf ("vax-dec-bsd4.3reno\n"); exit (0); -+# else -+ printf ("vax-dec-bsd\n"); exit (0); -+# endif -+# endif -+# else -+ printf ("vax-dec-bsd\n"); exit (0); -+# endif -+# else -+ printf ("vax-dec-ultrix\n"); exit (0); -+# endif -+#endif -+ -+#if defined (alliant) && defined (i860) -+ printf ("i860-alliant-bsd\n"); exit (0); -+#endif -+ -+ exit (1); -+} -+EOF -+ -+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && -+ { echo "$SYSTEM_NAME"; exit; } -+ -+# Apollos put the system type in the environment. -+ -+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } -+ -+# Convex versions that predate uname can use getsysinfo(1) -+ -+if [ -x /usr/convex/getsysinfo ] -+then -+ case `getsysinfo -f cpu_type` in -+ c1*) -+ echo c1-convex-bsd -+ exit ;; -+ c2*) -+ if getsysinfo -f scalar_acc -+ then echo c32-convex-bsd -+ else echo c2-convex-bsd -+ fi -+ exit ;; -+ c34*) -+ echo c34-convex-bsd -+ exit ;; -+ c38*) -+ echo c38-convex-bsd -+ exit ;; -+ c4*) -+ echo c4-convex-bsd -+ exit ;; -+ esac -+fi -+ -+cat >&2 < in order to provide the needed -+information to handle your system. -+ -+config.guess timestamp = $timestamp -+ -+uname -m = `(uname -m) 2>/dev/null || echo unknown` -+uname -r = `(uname -r) 2>/dev/null || echo unknown` -+uname -s = `(uname -s) 2>/dev/null || echo unknown` -+uname -v = `(uname -v) 2>/dev/null || echo unknown` -+ -+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -+/bin/uname -X = `(/bin/uname -X) 2>/dev/null` -+ -+hostinfo = `(hostinfo) 2>/dev/null` -+/bin/universe = `(/bin/universe) 2>/dev/null` -+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -+/bin/arch = `(/bin/arch) 2>/dev/null` -+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -+ -+UNAME_MACHINE = ${UNAME_MACHINE} -+UNAME_RELEASE = ${UNAME_RELEASE} -+UNAME_SYSTEM = ${UNAME_SYSTEM} -+UNAME_VERSION = ${UNAME_VERSION} -+EOF -+ -+exit 1 -+ -+# Local variables: -+# eval: (add-hook 'write-file-hooks 'time-stamp) -+# time-stamp-start: "timestamp='" -+# time-stamp-format: "%:y-%02m-%02d" -+# time-stamp-end: "'" -+# End: ---- /dev/null -+++ pmacct-0.12.1/config.sub -@@ -0,0 +1,1714 @@ -+#! /bin/sh -+# Configuration validation subroutine script. -+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -+# Free Software Foundation, Inc. -+ -+timestamp='2010-01-22' -+ -+# This file is (in principle) common to ALL GNU software. -+# The presence of a machine in this file suggests that SOME GNU software -+# can handle that machine. It does not imply ALL GNU software can. -+# -+# This file is free software; you can redistribute it and/or modify -+# it under the terms of the GNU General Public License as published by -+# the Free Software Foundation; either version 2 of the License, or -+# (at your option) any later version. -+# -+# This program is distributed in the hope that it will be useful, -+# but WITHOUT ANY WARRANTY; without even the implied warranty of -+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+# GNU General Public License for more details. -+# -+# You should have received a copy of the GNU General Public License -+# along with this program; if not, write to the Free Software -+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -+# 02110-1301, USA. -+# -+# As a special exception to the GNU General Public License, if you -+# distribute this file as part of a program that contains a -+# configuration script generated by Autoconf, you may include it under -+# the same distribution terms that you use for the rest of that program. -+ -+ -+# Please send patches to . Submit a context -+# diff and a properly formatted GNU ChangeLog entry. -+# -+# Configuration subroutine to validate and canonicalize a configuration type. -+# Supply the specified configuration type as an argument. -+# If it is invalid, we print an error message on stderr and exit with code 1. -+# Otherwise, we print the canonical config type on stdout and succeed. -+ -+# You can get the latest version of this script from: -+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD -+ -+# This file is supposed to be the same for all GNU packages -+# and recognize all the CPU types, system types and aliases -+# that are meaningful with *any* GNU software. -+# Each package is responsible for reporting which valid configurations -+# it does not support. The user should be able to distinguish -+# a failure to support a valid configuration from a meaningless -+# configuration. -+ -+# The goal of this file is to map all the various variations of a given -+# machine specification into a single specification in the form: -+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -+# or in some cases, the newer four-part form: -+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -+# It is wrong to echo any other type of specification. -+ -+me=`echo "$0" | sed -e 's,.*/,,'` -+ -+usage="\ -+Usage: $0 [OPTION] CPU-MFR-OPSYS -+ $0 [OPTION] ALIAS -+ -+Canonicalize a configuration name. -+ -+Operation modes: -+ -h, --help print this help, then exit -+ -t, --time-stamp print date of last modification, then exit -+ -v, --version print version number, then exit -+ -+Report bugs and patches to ." -+ -+version="\ -+GNU config.sub ($timestamp) -+ -+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free -+Software Foundation, Inc. -+ -+This is free software; see the source for copying conditions. There is NO -+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." -+ -+help=" -+Try \`$me --help' for more information." -+ -+# Parse command line -+while test $# -gt 0 ; do -+ case $1 in -+ --time-stamp | --time* | -t ) -+ echo "$timestamp" ; exit ;; -+ --version | -v ) -+ echo "$version" ; exit ;; -+ --help | --h* | -h ) -+ echo "$usage"; exit ;; -+ -- ) # Stop option processing -+ shift; break ;; -+ - ) # Use stdin as input. -+ break ;; -+ -* ) -+ echo "$me: invalid option $1$help" -+ exit 1 ;; -+ -+ *local*) -+ # First pass through any local machine types. -+ echo $1 -+ exit ;; -+ -+ * ) -+ break ;; -+ esac -+done -+ -+case $# in -+ 0) echo "$me: missing argument$help" >&2 -+ exit 1;; -+ 1) ;; -+ *) echo "$me: too many arguments$help" >&2 -+ exit 1;; -+esac -+ -+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -+# Here we must recognize all the valid KERNEL-OS combinations. -+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -+case $maybe_os in -+ nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ -+ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ -+ kopensolaris*-gnu* | \ -+ storm-chaos* | os2-emx* | rtmk-nova*) -+ os=-$maybe_os -+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` -+ ;; -+ *) -+ basic_machine=`echo $1 | sed 's/-[^-]*$//'` -+ if [ $basic_machine != $1 ] -+ then os=`echo $1 | sed 's/.*-/-/'` -+ else os=; fi -+ ;; -+esac -+ -+### Let's recognize common machines as not being operating systems so -+### that things like config.sub decstation-3100 work. We also -+### recognize some manufacturers as not being operating systems, so we -+### can provide default operating systems below. -+case $os in -+ -sun*os*) -+ # Prevent following clause from handling this invalid input. -+ ;; -+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -+ -apple | -axis | -knuth | -cray | -microblaze) -+ os= -+ basic_machine=$1 -+ ;; -+ -bluegene*) -+ os=-cnk -+ ;; -+ -sim | -cisco | -oki | -wec | -winbond) -+ os= -+ basic_machine=$1 -+ ;; -+ -scout) -+ ;; -+ -wrs) -+ os=-vxworks -+ basic_machine=$1 -+ ;; -+ -chorusos*) -+ os=-chorusos -+ basic_machine=$1 -+ ;; -+ -chorusrdb) -+ os=-chorusrdb -+ basic_machine=$1 -+ ;; -+ -hiux*) -+ os=-hiuxwe2 -+ ;; -+ -sco6) -+ os=-sco5v6 -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco5) -+ os=-sco3.2v5 -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco4) -+ os=-sco3.2v4 -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco3.2.[4-9]*) -+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco3.2v[4-9]*) -+ # Don't forget version if it is 3.2v4 or newer. -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco5v6*) -+ # Don't forget version if it is 3.2v4 or newer. -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -sco*) -+ os=-sco3.2v2 -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -udk*) -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -isc) -+ os=-isc2.2 -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -clix*) -+ basic_machine=clipper-intergraph -+ ;; -+ -isc*) -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` -+ ;; -+ -lynx*) -+ os=-lynxos -+ ;; -+ -ptx*) -+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` -+ ;; -+ -windowsnt*) -+ os=`echo $os | sed -e 's/windowsnt/winnt/'` -+ ;; -+ -psos*) -+ os=-psos -+ ;; -+ -mint | -mint[0-9]*) -+ basic_machine=m68k-atari -+ os=-mint -+ ;; -+esac -+ -+# Decode aliases for certain CPU-COMPANY combinations. -+case $basic_machine in -+ # Recognize the basic CPU types without company name. -+ # Some are omitted here because they have special meanings below. -+ 1750a | 580 \ -+ | a29k \ -+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ -+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ -+ | am33_2.0 \ -+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ -+ | bfin \ -+ | c4x | clipper \ -+ | d10v | d30v | dlx | dsp16xx \ -+ | fido | fr30 | frv \ -+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ -+ | i370 | i860 | i960 | ia64 \ -+ | ip2k | iq2000 \ -+ | lm32 \ -+ | m32c | m32r | m32rle | m68000 | m68k | m88k \ -+ | maxq | mb | microblaze | mcore | mep | metag \ -+ | mips | mipsbe | mipseb | mipsel | mipsle \ -+ | mips16 \ -+ | mips64 | mips64el \ -+ | mips64octeon | mips64octeonel \ -+ | mips64orion | mips64orionel \ -+ | mips64r5900 | mips64r5900el \ -+ | mips64vr | mips64vrel \ -+ | mips64vr4100 | mips64vr4100el \ -+ | mips64vr4300 | mips64vr4300el \ -+ | mips64vr5000 | mips64vr5000el \ -+ | mips64vr5900 | mips64vr5900el \ -+ | mipsisa32 | mipsisa32el \ -+ | mipsisa32r2 | mipsisa32r2el \ -+ | mipsisa64 | mipsisa64el \ -+ | mipsisa64r2 | mipsisa64r2el \ -+ | mipsisa64sb1 | mipsisa64sb1el \ -+ | mipsisa64sr71k | mipsisa64sr71kel \ -+ | mipstx39 | mipstx39el \ -+ | mn10200 | mn10300 \ -+ | moxie \ -+ | mt \ -+ | msp430 \ -+ | nios | nios2 \ -+ | ns16k | ns32k \ -+ | or32 \ -+ | pdp10 | pdp11 | pj | pjl \ -+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ -+ | pyramid \ -+ | rx \ -+ | score \ -+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ -+ | sh64 | sh64le \ -+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ -+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ -+ | spu | strongarm \ -+ | tahoe | thumb | tic4x | tic80 | tron \ -+ | ubicom32 \ -+ | v850 | v850e \ -+ | we32k \ -+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ -+ | z8k | z80) -+ basic_machine=$basic_machine-unknown -+ ;; -+ m6811 | m68hc11 | m6812 | m68hc12 | picochip) -+ # Motorola 68HC11/12. -+ basic_machine=$basic_machine-unknown -+ os=-none -+ ;; -+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) -+ ;; -+ ms1) -+ basic_machine=mt-unknown -+ ;; -+ -+ # We use `pc' rather than `unknown' -+ # because (1) that's what they normally are, and -+ # (2) the word "unknown" tends to confuse beginning users. -+ i*86 | x86_64) -+ basic_machine=$basic_machine-pc -+ ;; -+ # Object if more than one company name word. -+ *-*-*) -+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 -+ exit 1 -+ ;; -+ # Recognize the basic CPU types with company name. -+ 580-* \ -+ | a29k-* \ -+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ -+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ -+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ -+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ -+ | avr-* | avr32-* \ -+ | bfin-* | bs2000-* \ -+ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ -+ | clipper-* | craynv-* | cydra-* \ -+ | d10v-* | d30v-* | dlx-* \ -+ | elxsi-* \ -+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ -+ | h8300-* | h8500-* \ -+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ -+ | i*86-* | i860-* | i960-* | ia64-* \ -+ | ip2k-* | iq2000-* \ -+ | lm32-* \ -+ | m32c-* | m32r-* | m32rle-* \ -+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ -+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ -+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ -+ | mips16-* \ -+ | mips64-* | mips64el-* \ -+ | mips64octeon-* | mips64octeonel-* \ -+ | mips64orion-* | mips64orionel-* \ -+ | mips64r5900-* | mips64r5900el-* \ -+ | mips64vr-* | mips64vrel-* \ -+ | mips64vr4100-* | mips64vr4100el-* \ -+ | mips64vr4300-* | mips64vr4300el-* \ -+ | mips64vr5000-* | mips64vr5000el-* \ -+ | mips64vr5900-* | mips64vr5900el-* \ -+ | mipsisa32-* | mipsisa32el-* \ -+ | mipsisa32r2-* | mipsisa32r2el-* \ -+ | mipsisa64-* | mipsisa64el-* \ -+ | mipsisa64r2-* | mipsisa64r2el-* \ -+ | mipsisa64sb1-* | mipsisa64sb1el-* \ -+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ -+ | mipstx39-* | mipstx39el-* \ -+ | mmix-* \ -+ | mt-* \ -+ | msp430-* \ -+ | nios-* | nios2-* \ -+ | none-* | np1-* | ns16k-* | ns32k-* \ -+ | orion-* \ -+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ -+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ -+ | pyramid-* \ -+ | romp-* | rs6000-* | rx-* \ -+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ -+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ -+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ -+ | sparclite-* \ -+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ -+ | tahoe-* | thumb-* \ -+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ -+ | tile-* | tilegx-* \ -+ | tron-* \ -+ | ubicom32-* \ -+ | v850-* | v850e-* | vax-* \ -+ | we32k-* \ -+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ -+ | xstormy16-* | xtensa*-* \ -+ | ymp-* \ -+ | z8k-* | z80-*) -+ ;; -+ # Recognize the basic CPU types without company name, with glob match. -+ xtensa*) -+ basic_machine=$basic_machine-unknown -+ ;; -+ # Recognize the various machine names and aliases which stand -+ # for a CPU type and a company and sometimes even an OS. -+ 386bsd) -+ basic_machine=i386-unknown -+ os=-bsd -+ ;; -+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) -+ basic_machine=m68000-att -+ ;; -+ 3b*) -+ basic_machine=we32k-att -+ ;; -+ a29khif) -+ basic_machine=a29k-amd -+ os=-udi -+ ;; -+ abacus) -+ basic_machine=abacus-unknown -+ ;; -+ adobe68k) -+ basic_machine=m68010-adobe -+ os=-scout -+ ;; -+ alliant | fx80) -+ basic_machine=fx80-alliant -+ ;; -+ altos | altos3068) -+ basic_machine=m68k-altos -+ ;; -+ am29k) -+ basic_machine=a29k-none -+ os=-bsd -+ ;; -+ amd64) -+ basic_machine=x86_64-pc -+ ;; -+ amd64-*) -+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ amdahl) -+ basic_machine=580-amdahl -+ os=-sysv -+ ;; -+ amiga | amiga-*) -+ basic_machine=m68k-unknown -+ ;; -+ amigaos | amigados) -+ basic_machine=m68k-unknown -+ os=-amigaos -+ ;; -+ amigaunix | amix) -+ basic_machine=m68k-unknown -+ os=-sysv4 -+ ;; -+ apollo68) -+ basic_machine=m68k-apollo -+ os=-sysv -+ ;; -+ apollo68bsd) -+ basic_machine=m68k-apollo -+ os=-bsd -+ ;; -+ aros) -+ basic_machine=i386-pc -+ os=-aros -+ ;; -+ aux) -+ basic_machine=m68k-apple -+ os=-aux -+ ;; -+ balance) -+ basic_machine=ns32k-sequent -+ os=-dynix -+ ;; -+ blackfin) -+ basic_machine=bfin-unknown -+ os=-linux -+ ;; -+ blackfin-*) -+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` -+ os=-linux -+ ;; -+ bluegene*) -+ basic_machine=powerpc-ibm -+ os=-cnk -+ ;; -+ c90) -+ basic_machine=c90-cray -+ os=-unicos -+ ;; -+ cegcc) -+ basic_machine=arm-unknown -+ os=-cegcc -+ ;; -+ convex-c1) -+ basic_machine=c1-convex -+ os=-bsd -+ ;; -+ convex-c2) -+ basic_machine=c2-convex -+ os=-bsd -+ ;; -+ convex-c32) -+ basic_machine=c32-convex -+ os=-bsd -+ ;; -+ convex-c34) -+ basic_machine=c34-convex -+ os=-bsd -+ ;; -+ convex-c38) -+ basic_machine=c38-convex -+ os=-bsd -+ ;; -+ cray | j90) -+ basic_machine=j90-cray -+ os=-unicos -+ ;; -+ craynv) -+ basic_machine=craynv-cray -+ os=-unicosmp -+ ;; -+ cr16) -+ basic_machine=cr16-unknown -+ os=-elf -+ ;; -+ crds | unos) -+ basic_machine=m68k-crds -+ ;; -+ crisv32 | crisv32-* | etraxfs*) -+ basic_machine=crisv32-axis -+ ;; -+ cris | cris-* | etrax*) -+ basic_machine=cris-axis -+ ;; -+ crx) -+ basic_machine=crx-unknown -+ os=-elf -+ ;; -+ da30 | da30-*) -+ basic_machine=m68k-da30 -+ ;; -+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) -+ basic_machine=mips-dec -+ ;; -+ decsystem10* | dec10*) -+ basic_machine=pdp10-dec -+ os=-tops10 -+ ;; -+ decsystem20* | dec20*) -+ basic_machine=pdp10-dec -+ os=-tops20 -+ ;; -+ delta | 3300 | motorola-3300 | motorola-delta \ -+ | 3300-motorola | delta-motorola) -+ basic_machine=m68k-motorola -+ ;; -+ delta88) -+ basic_machine=m88k-motorola -+ os=-sysv3 -+ ;; -+ dicos) -+ basic_machine=i686-pc -+ os=-dicos -+ ;; -+ djgpp) -+ basic_machine=i586-pc -+ os=-msdosdjgpp -+ ;; -+ dpx20 | dpx20-*) -+ basic_machine=rs6000-bull -+ os=-bosx -+ ;; -+ dpx2* | dpx2*-bull) -+ basic_machine=m68k-bull -+ os=-sysv3 -+ ;; -+ ebmon29k) -+ basic_machine=a29k-amd -+ os=-ebmon -+ ;; -+ elxsi) -+ basic_machine=elxsi-elxsi -+ os=-bsd -+ ;; -+ encore | umax | mmax) -+ basic_machine=ns32k-encore -+ ;; -+ es1800 | OSE68k | ose68k | ose | OSE) -+ basic_machine=m68k-ericsson -+ os=-ose -+ ;; -+ fx2800) -+ basic_machine=i860-alliant -+ ;; -+ genix) -+ basic_machine=ns32k-ns -+ ;; -+ gmicro) -+ basic_machine=tron-gmicro -+ os=-sysv -+ ;; -+ go32) -+ basic_machine=i386-pc -+ os=-go32 -+ ;; -+ h3050r* | hiux*) -+ basic_machine=hppa1.1-hitachi -+ os=-hiuxwe2 -+ ;; -+ h8300hms) -+ basic_machine=h8300-hitachi -+ os=-hms -+ ;; -+ h8300xray) -+ basic_machine=h8300-hitachi -+ os=-xray -+ ;; -+ h8500hms) -+ basic_machine=h8500-hitachi -+ os=-hms -+ ;; -+ harris) -+ basic_machine=m88k-harris -+ os=-sysv3 -+ ;; -+ hp300-*) -+ basic_machine=m68k-hp -+ ;; -+ hp300bsd) -+ basic_machine=m68k-hp -+ os=-bsd -+ ;; -+ hp300hpux) -+ basic_machine=m68k-hp -+ os=-hpux -+ ;; -+ hp3k9[0-9][0-9] | hp9[0-9][0-9]) -+ basic_machine=hppa1.0-hp -+ ;; -+ hp9k2[0-9][0-9] | hp9k31[0-9]) -+ basic_machine=m68000-hp -+ ;; -+ hp9k3[2-9][0-9]) -+ basic_machine=m68k-hp -+ ;; -+ hp9k6[0-9][0-9] | hp6[0-9][0-9]) -+ basic_machine=hppa1.0-hp -+ ;; -+ hp9k7[0-79][0-9] | hp7[0-79][0-9]) -+ basic_machine=hppa1.1-hp -+ ;; -+ hp9k78[0-9] | hp78[0-9]) -+ # FIXME: really hppa2.0-hp -+ basic_machine=hppa1.1-hp -+ ;; -+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) -+ # FIXME: really hppa2.0-hp -+ basic_machine=hppa1.1-hp -+ ;; -+ hp9k8[0-9][13679] | hp8[0-9][13679]) -+ basic_machine=hppa1.1-hp -+ ;; -+ hp9k8[0-9][0-9] | hp8[0-9][0-9]) -+ basic_machine=hppa1.0-hp -+ ;; -+ hppa-next) -+ os=-nextstep3 -+ ;; -+ hppaosf) -+ basic_machine=hppa1.1-hp -+ os=-osf -+ ;; -+ hppro) -+ basic_machine=hppa1.1-hp -+ os=-proelf -+ ;; -+ i370-ibm* | ibm*) -+ basic_machine=i370-ibm -+ ;; -+# I'm not sure what "Sysv32" means. Should this be sysv3.2? -+ i*86v32) -+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` -+ os=-sysv32 -+ ;; -+ i*86v4*) -+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` -+ os=-sysv4 -+ ;; -+ i*86v) -+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` -+ os=-sysv -+ ;; -+ i*86sol2) -+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` -+ os=-solaris2 -+ ;; -+ i386mach) -+ basic_machine=i386-mach -+ os=-mach -+ ;; -+ i386-vsta | vsta) -+ basic_machine=i386-unknown -+ os=-vsta -+ ;; -+ iris | iris4d) -+ basic_machine=mips-sgi -+ case $os in -+ -irix*) -+ ;; -+ *) -+ os=-irix4 -+ ;; -+ esac -+ ;; -+ isi68 | isi) -+ basic_machine=m68k-isi -+ os=-sysv -+ ;; -+ m68knommu) -+ basic_machine=m68k-unknown -+ os=-linux -+ ;; -+ m68knommu-*) -+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` -+ os=-linux -+ ;; -+ m88k-omron*) -+ basic_machine=m88k-omron -+ ;; -+ magnum | m3230) -+ basic_machine=mips-mips -+ os=-sysv -+ ;; -+ merlin) -+ basic_machine=ns32k-utek -+ os=-sysv -+ ;; -+ microblaze) -+ basic_machine=microblaze-xilinx -+ ;; -+ mingw32) -+ basic_machine=i386-pc -+ os=-mingw32 -+ ;; -+ mingw32ce) -+ basic_machine=arm-unknown -+ os=-mingw32ce -+ ;; -+ miniframe) -+ basic_machine=m68000-convergent -+ ;; -+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) -+ basic_machine=m68k-atari -+ os=-mint -+ ;; -+ mips3*-*) -+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` -+ ;; -+ mips3*) -+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown -+ ;; -+ monitor) -+ basic_machine=m68k-rom68k -+ os=-coff -+ ;; -+ morphos) -+ basic_machine=powerpc-unknown -+ os=-morphos -+ ;; -+ msdos) -+ basic_machine=i386-pc -+ os=-msdos -+ ;; -+ ms1-*) -+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` -+ ;; -+ mvs) -+ basic_machine=i370-ibm -+ os=-mvs -+ ;; -+ ncr3000) -+ basic_machine=i486-ncr -+ os=-sysv4 -+ ;; -+ netbsd386) -+ basic_machine=i386-unknown -+ os=-netbsd -+ ;; -+ netwinder) -+ basic_machine=armv4l-rebel -+ os=-linux -+ ;; -+ news | news700 | news800 | news900) -+ basic_machine=m68k-sony -+ os=-newsos -+ ;; -+ news1000) -+ basic_machine=m68030-sony -+ os=-newsos -+ ;; -+ news-3600 | risc-news) -+ basic_machine=mips-sony -+ os=-newsos -+ ;; -+ necv70) -+ basic_machine=v70-nec -+ os=-sysv -+ ;; -+ next | m*-next ) -+ basic_machine=m68k-next -+ case $os in -+ -nextstep* ) -+ ;; -+ -ns2*) -+ os=-nextstep2 -+ ;; -+ *) -+ os=-nextstep3 -+ ;; -+ esac -+ ;; -+ nh3000) -+ basic_machine=m68k-harris -+ os=-cxux -+ ;; -+ nh[45]000) -+ basic_machine=m88k-harris -+ os=-cxux -+ ;; -+ nindy960) -+ basic_machine=i960-intel -+ os=-nindy -+ ;; -+ mon960) -+ basic_machine=i960-intel -+ os=-mon960 -+ ;; -+ nonstopux) -+ basic_machine=mips-compaq -+ os=-nonstopux -+ ;; -+ np1) -+ basic_machine=np1-gould -+ ;; -+ nsr-tandem) -+ basic_machine=nsr-tandem -+ ;; -+ op50n-* | op60c-*) -+ basic_machine=hppa1.1-oki -+ os=-proelf -+ ;; -+ openrisc | openrisc-*) -+ basic_machine=or32-unknown -+ ;; -+ os400) -+ basic_machine=powerpc-ibm -+ os=-os400 -+ ;; -+ OSE68000 | ose68000) -+ basic_machine=m68000-ericsson -+ os=-ose -+ ;; -+ os68k) -+ basic_machine=m68k-none -+ os=-os68k -+ ;; -+ pa-hitachi) -+ basic_machine=hppa1.1-hitachi -+ os=-hiuxwe2 -+ ;; -+ paragon) -+ basic_machine=i860-intel -+ os=-osf -+ ;; -+ parisc) -+ basic_machine=hppa-unknown -+ os=-linux -+ ;; -+ parisc-*) -+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` -+ os=-linux -+ ;; -+ pbd) -+ basic_machine=sparc-tti -+ ;; -+ pbb) -+ basic_machine=m68k-tti -+ ;; -+ pc532 | pc532-*) -+ basic_machine=ns32k-pc532 -+ ;; -+ pc98) -+ basic_machine=i386-pc -+ ;; -+ pc98-*) -+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ pentium | p5 | k5 | k6 | nexgen | viac3) -+ basic_machine=i586-pc -+ ;; -+ pentiumpro | p6 | 6x86 | athlon | athlon_*) -+ basic_machine=i686-pc -+ ;; -+ pentiumii | pentium2 | pentiumiii | pentium3) -+ basic_machine=i686-pc -+ ;; -+ pentium4) -+ basic_machine=i786-pc -+ ;; -+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) -+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ pentiumpro-* | p6-* | 6x86-* | athlon-*) -+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) -+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ pentium4-*) -+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ pn) -+ basic_machine=pn-gould -+ ;; -+ power) basic_machine=power-ibm -+ ;; -+ ppc) basic_machine=powerpc-unknown -+ ;; -+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ ppcle | powerpclittle | ppc-le | powerpc-little) -+ basic_machine=powerpcle-unknown -+ ;; -+ ppcle-* | powerpclittle-*) -+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ ppc64) basic_machine=powerpc64-unknown -+ ;; -+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ ppc64le | powerpc64little | ppc64-le | powerpc64-little) -+ basic_machine=powerpc64le-unknown -+ ;; -+ ppc64le-* | powerpc64little-*) -+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` -+ ;; -+ ps2) -+ basic_machine=i386-ibm -+ ;; -+ pw32) -+ basic_machine=i586-unknown -+ os=-pw32 -+ ;; -+ rdos) -+ basic_machine=i386-pc -+ os=-rdos -+ ;; -+ rom68k) -+ basic_machine=m68k-rom68k -+ os=-coff -+ ;; -+ rm[46]00) -+ basic_machine=mips-siemens -+ ;; -+ rtpc | rtpc-*) -+ basic_machine=romp-ibm -+ ;; -+ s390 | s390-*) -+ basic_machine=s390-ibm -+ ;; -+ s390x | s390x-*) -+ basic_machine=s390x-ibm -+ ;; -+ sa29200) -+ basic_machine=a29k-amd -+ os=-udi -+ ;; -+ sb1) -+ basic_machine=mipsisa64sb1-unknown -+ ;; -+ sb1el) -+ basic_machine=mipsisa64sb1el-unknown -+ ;; -+ sde) -+ basic_machine=mipsisa32-sde -+ os=-elf -+ ;; -+ sei) -+ basic_machine=mips-sei -+ os=-seiux -+ ;; -+ sequent) -+ basic_machine=i386-sequent -+ ;; -+ sh) -+ basic_machine=sh-hitachi -+ os=-hms -+ ;; -+ sh5el) -+ basic_machine=sh5le-unknown -+ ;; -+ sh64) -+ basic_machine=sh64-unknown -+ ;; -+ sparclite-wrs | simso-wrs) -+ basic_machine=sparclite-wrs -+ os=-vxworks -+ ;; -+ sps7) -+ basic_machine=m68k-bull -+ os=-sysv2 -+ ;; -+ spur) -+ basic_machine=spur-unknown -+ ;; -+ st2000) -+ basic_machine=m68k-tandem -+ ;; -+ stratus) -+ basic_machine=i860-stratus -+ os=-sysv4 -+ ;; -+ sun2) -+ basic_machine=m68000-sun -+ ;; -+ sun2os3) -+ basic_machine=m68000-sun -+ os=-sunos3 -+ ;; -+ sun2os4) -+ basic_machine=m68000-sun -+ os=-sunos4 -+ ;; -+ sun3os3) -+ basic_machine=m68k-sun -+ os=-sunos3 -+ ;; -+ sun3os4) -+ basic_machine=m68k-sun -+ os=-sunos4 -+ ;; -+ sun4os3) -+ basic_machine=sparc-sun -+ os=-sunos3 -+ ;; -+ sun4os4) -+ basic_machine=sparc-sun -+ os=-sunos4 -+ ;; -+ sun4sol2) -+ basic_machine=sparc-sun -+ os=-solaris2 -+ ;; -+ sun3 | sun3-*) -+ basic_machine=m68k-sun -+ ;; -+ sun4) -+ basic_machine=sparc-sun -+ ;; -+ sun386 | sun386i | roadrunner) -+ basic_machine=i386-sun -+ ;; -+ sv1) -+ basic_machine=sv1-cray -+ os=-unicos -+ ;; -+ symmetry) -+ basic_machine=i386-sequent -+ os=-dynix -+ ;; -+ t3e) -+ basic_machine=alphaev5-cray -+ os=-unicos -+ ;; -+ t90) -+ basic_machine=t90-cray -+ os=-unicos -+ ;; -+ tic54x | c54x*) -+ basic_machine=tic54x-unknown -+ os=-coff -+ ;; -+ tic55x | c55x*) -+ basic_machine=tic55x-unknown -+ os=-coff -+ ;; -+ tic6x | c6x*) -+ basic_machine=tic6x-unknown -+ os=-coff -+ ;; -+ # This must be matched before tile*. -+ tilegx*) -+ basic_machine=tilegx-unknown -+ os=-linux-gnu -+ ;; -+ tile*) -+ basic_machine=tile-unknown -+ os=-linux-gnu -+ ;; -+ tx39) -+ basic_machine=mipstx39-unknown -+ ;; -+ tx39el) -+ basic_machine=mipstx39el-unknown -+ ;; -+ toad1) -+ basic_machine=pdp10-xkl -+ os=-tops20 -+ ;; -+ tower | tower-32) -+ basic_machine=m68k-ncr -+ ;; -+ tpf) -+ basic_machine=s390x-ibm -+ os=-tpf -+ ;; -+ udi29k) -+ basic_machine=a29k-amd -+ os=-udi -+ ;; -+ ultra3) -+ basic_machine=a29k-nyu -+ os=-sym1 -+ ;; -+ v810 | necv810) -+ basic_machine=v810-nec -+ os=-none -+ ;; -+ vaxv) -+ basic_machine=vax-dec -+ os=-sysv -+ ;; -+ vms) -+ basic_machine=vax-dec -+ os=-vms -+ ;; -+ vpp*|vx|vx-*) -+ basic_machine=f301-fujitsu -+ ;; -+ vxworks960) -+ basic_machine=i960-wrs -+ os=-vxworks -+ ;; -+ vxworks68) -+ basic_machine=m68k-wrs -+ os=-vxworks -+ ;; -+ vxworks29k) -+ basic_machine=a29k-wrs -+ os=-vxworks -+ ;; -+ w65*) -+ basic_machine=w65-wdc -+ os=-none -+ ;; -+ w89k-*) -+ basic_machine=hppa1.1-winbond -+ os=-proelf -+ ;; -+ xbox) -+ basic_machine=i686-pc -+ os=-mingw32 -+ ;; -+ xps | xps100) -+ basic_machine=xps100-honeywell -+ ;; -+ ymp) -+ basic_machine=ymp-cray -+ os=-unicos -+ ;; -+ z8k-*-coff) -+ basic_machine=z8k-unknown -+ os=-sim -+ ;; -+ z80-*-coff) -+ basic_machine=z80-unknown -+ os=-sim -+ ;; -+ none) -+ basic_machine=none-none -+ os=-none -+ ;; -+ -+# Here we handle the default manufacturer of certain CPU types. It is in -+# some cases the only manufacturer, in others, it is the most popular. -+ w89k) -+ basic_machine=hppa1.1-winbond -+ ;; -+ op50n) -+ basic_machine=hppa1.1-oki -+ ;; -+ op60c) -+ basic_machine=hppa1.1-oki -+ ;; -+ romp) -+ basic_machine=romp-ibm -+ ;; -+ mmix) -+ basic_machine=mmix-knuth -+ ;; -+ rs6000) -+ basic_machine=rs6000-ibm -+ ;; -+ vax) -+ basic_machine=vax-dec -+ ;; -+ pdp10) -+ # there are many clones, so DEC is not a safe bet -+ basic_machine=pdp10-unknown -+ ;; -+ pdp11) -+ basic_machine=pdp11-dec -+ ;; -+ we32k) -+ basic_machine=we32k-att -+ ;; -+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) -+ basic_machine=sh-unknown -+ ;; -+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) -+ basic_machine=sparc-sun -+ ;; -+ cydra) -+ basic_machine=cydra-cydrome -+ ;; -+ orion) -+ basic_machine=orion-highlevel -+ ;; -+ orion105) -+ basic_machine=clipper-highlevel -+ ;; -+ mac | mpw | mac-mpw) -+ basic_machine=m68k-apple -+ ;; -+ pmac | pmac-mpw) -+ basic_machine=powerpc-apple -+ ;; -+ *-unknown) -+ # Make sure to match an already-canonicalized machine name. -+ ;; -+ *) -+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 -+ exit 1 -+ ;; -+esac -+ -+# Here we canonicalize certain aliases for manufacturers. -+case $basic_machine in -+ *-digital*) -+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` -+ ;; -+ *-commodore*) -+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` -+ ;; -+ *) -+ ;; -+esac -+ -+# Decode manufacturer-specific aliases for certain operating systems. -+ -+if [ x"$os" != x"" ] -+then -+case $os in -+ # First match some system type aliases -+ # that might get confused with valid system types. -+ # -solaris* is a basic system type, with this one exception. -+ -auroraux) -+ os=-auroraux -+ ;; -+ -solaris1 | -solaris1.*) -+ os=`echo $os | sed -e 's|solaris1|sunos4|'` -+ ;; -+ -solaris) -+ os=-solaris2 -+ ;; -+ -svr4*) -+ os=-sysv4 -+ ;; -+ -unixware*) -+ os=-sysv4.2uw -+ ;; -+ -gnu/linux*) -+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` -+ ;; -+ # First accept the basic system types. -+ # The portable systems comes first. -+ # Each alternative MUST END IN A *, to match a version number. -+ # -sysv* is not here because it comes later, after sysvr4. -+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ -+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ -+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ -+ | -sym* | -kopensolaris* \ -+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ -+ | -aos* | -aros* \ -+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ -+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ -+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ -+ | -openbsd* | -solidbsd* \ -+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ -+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ -+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ -+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ -+ | -chorusos* | -chorusrdb* | -cegcc* \ -+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ -+ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ -+ | -uxpv* | -beos* | -mpeix* | -udk* \ -+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ -+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ -+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ -+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ -+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ -+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ -+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) -+ # Remember, each alternative MUST END IN *, to match a version number. -+ ;; -+ -qnx*) -+ case $basic_machine in -+ x86-* | i*86-*) -+ ;; -+ *) -+ os=-nto$os -+ ;; -+ esac -+ ;; -+ -nto-qnx*) -+ ;; -+ -nto*) -+ os=`echo $os | sed -e 's|nto|nto-qnx|'` -+ ;; -+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ -+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ -+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) -+ ;; -+ -mac*) -+ os=`echo $os | sed -e 's|mac|macos|'` -+ ;; -+ -linux-dietlibc) -+ os=-linux-dietlibc -+ ;; -+ -linux*) -+ os=`echo $os | sed -e 's|linux|linux-gnu|'` -+ ;; -+ -sunos5*) -+ os=`echo $os | sed -e 's|sunos5|solaris2|'` -+ ;; -+ -sunos6*) -+ os=`echo $os | sed -e 's|sunos6|solaris3|'` -+ ;; -+ -opened*) -+ os=-openedition -+ ;; -+ -os400*) -+ os=-os400 -+ ;; -+ -wince*) -+ os=-wince -+ ;; -+ -osfrose*) -+ os=-osfrose -+ ;; -+ -osf*) -+ os=-osf -+ ;; -+ -utek*) -+ os=-bsd -+ ;; -+ -dynix*) -+ os=-bsd -+ ;; -+ -acis*) -+ os=-aos -+ ;; -+ -atheos*) -+ os=-atheos -+ ;; -+ -syllable*) -+ os=-syllable -+ ;; -+ -386bsd) -+ os=-bsd -+ ;; -+ -ctix* | -uts*) -+ os=-sysv -+ ;; -+ -nova*) -+ os=-rtmk-nova -+ ;; -+ -ns2 ) -+ os=-nextstep2 -+ ;; -+ -nsk*) -+ os=-nsk -+ ;; -+ # Preserve the version number of sinix5. -+ -sinix5.*) -+ os=`echo $os | sed -e 's|sinix|sysv|'` -+ ;; -+ -sinix*) -+ os=-sysv4 -+ ;; -+ -tpf*) -+ os=-tpf -+ ;; -+ -triton*) -+ os=-sysv3 -+ ;; -+ -oss*) -+ os=-sysv3 -+ ;; -+ -svr4) -+ os=-sysv4 -+ ;; -+ -svr3) -+ os=-sysv3 -+ ;; -+ -sysvr4) -+ os=-sysv4 -+ ;; -+ # This must come after -sysvr4. -+ -sysv*) -+ ;; -+ -ose*) -+ os=-ose -+ ;; -+ -es1800*) -+ os=-ose -+ ;; -+ -xenix) -+ os=-xenix -+ ;; -+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) -+ os=-mint -+ ;; -+ -aros*) -+ os=-aros -+ ;; -+ -kaos*) -+ os=-kaos -+ ;; -+ -zvmoe) -+ os=-zvmoe -+ ;; -+ -dicos*) -+ os=-dicos -+ ;; -+ -nacl*) -+ ;; -+ -none) -+ ;; -+ *) -+ # Get rid of the `-' at the beginning of $os. -+ os=`echo $os | sed 's/[^-]*-//'` -+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 -+ exit 1 -+ ;; -+esac -+else -+ -+# Here we handle the default operating systems that come with various machines. -+# The value should be what the vendor currently ships out the door with their -+# machine or put another way, the most popular os provided with the machine. -+ -+# Note that if you're going to try to match "-MANUFACTURER" here (say, -+# "-sun"), then you have to tell the case statement up towards the top -+# that MANUFACTURER isn't an operating system. Otherwise, code above -+# will signal an error saying that MANUFACTURER isn't an operating -+# system, and we'll never get to this point. -+ -+case $basic_machine in -+ score-*) -+ os=-elf -+ ;; -+ spu-*) -+ os=-elf -+ ;; -+ *-acorn) -+ os=-riscix1.2 -+ ;; -+ arm*-rebel) -+ os=-linux -+ ;; -+ arm*-semi) -+ os=-aout -+ ;; -+ c4x-* | tic4x-*) -+ os=-coff -+ ;; -+ # This must come before the *-dec entry. -+ pdp10-*) -+ os=-tops20 -+ ;; -+ pdp11-*) -+ os=-none -+ ;; -+ *-dec | vax-*) -+ os=-ultrix4.2 -+ ;; -+ m68*-apollo) -+ os=-domain -+ ;; -+ i386-sun) -+ os=-sunos4.0.2 -+ ;; -+ m68000-sun) -+ os=-sunos3 -+ # This also exists in the configure program, but was not the -+ # default. -+ # os=-sunos4 -+ ;; -+ m68*-cisco) -+ os=-aout -+ ;; -+ mep-*) -+ os=-elf -+ ;; -+ mips*-cisco) -+ os=-elf -+ ;; -+ mips*-*) -+ os=-elf -+ ;; -+ or32-*) -+ os=-coff -+ ;; -+ *-tti) # must be before sparc entry or we get the wrong os. -+ os=-sysv3 -+ ;; -+ sparc-* | *-sun) -+ os=-sunos4.1.1 -+ ;; -+ *-be) -+ os=-beos -+ ;; -+ *-haiku) -+ os=-haiku -+ ;; -+ *-ibm) -+ os=-aix -+ ;; -+ *-knuth) -+ os=-mmixware -+ ;; -+ *-wec) -+ os=-proelf -+ ;; -+ *-winbond) -+ os=-proelf -+ ;; -+ *-oki) -+ os=-proelf -+ ;; -+ *-hp) -+ os=-hpux -+ ;; -+ *-hitachi) -+ os=-hiux -+ ;; -+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) -+ os=-sysv -+ ;; -+ *-cbm) -+ os=-amigaos -+ ;; -+ *-dg) -+ os=-dgux -+ ;; -+ *-dolphin) -+ os=-sysv3 -+ ;; -+ m68k-ccur) -+ os=-rtu -+ ;; -+ m88k-omron*) -+ os=-luna -+ ;; -+ *-next ) -+ os=-nextstep -+ ;; -+ *-sequent) -+ os=-ptx -+ ;; -+ *-crds) -+ os=-unos -+ ;; -+ *-ns) -+ os=-genix -+ ;; -+ i370-*) -+ os=-mvs -+ ;; -+ *-next) -+ os=-nextstep3 -+ ;; -+ *-gould) -+ os=-sysv -+ ;; -+ *-highlevel) -+ os=-bsd -+ ;; -+ *-encore) -+ os=-bsd -+ ;; -+ *-sgi) -+ os=-irix -+ ;; -+ *-siemens) -+ os=-sysv4 -+ ;; -+ *-masscomp) -+ os=-rtu -+ ;; -+ f30[01]-fujitsu | f700-fujitsu) -+ os=-uxpv -+ ;; -+ *-rom68k) -+ os=-coff -+ ;; -+ *-*bug) -+ os=-coff -+ ;; -+ *-apple) -+ os=-macos -+ ;; -+ *-atari*) -+ os=-mint -+ ;; -+ *) -+ os=-none -+ ;; -+esac -+fi -+ -+# Here we handle the case where we know the os, and the CPU type, but not the -+# manufacturer. We pick the logical manufacturer. -+vendor=unknown -+case $basic_machine in -+ *-unknown) -+ case $os in -+ -riscix*) -+ vendor=acorn -+ ;; -+ -sunos*) -+ vendor=sun -+ ;; -+ -cnk*|-aix*) -+ vendor=ibm -+ ;; -+ -beos*) -+ vendor=be -+ ;; -+ -hpux*) -+ vendor=hp -+ ;; -+ -mpeix*) -+ vendor=hp -+ ;; -+ -hiux*) -+ vendor=hitachi -+ ;; -+ -unos*) -+ vendor=crds -+ ;; -+ -dgux*) -+ vendor=dg -+ ;; -+ -luna*) -+ vendor=omron -+ ;; -+ -genix*) -+ vendor=ns -+ ;; -+ -mvs* | -opened*) -+ vendor=ibm -+ ;; -+ -os400*) -+ vendor=ibm -+ ;; -+ -ptx*) -+ vendor=sequent -+ ;; -+ -tpf*) -+ vendor=ibm -+ ;; -+ -vxsim* | -vxworks* | -windiss*) -+ vendor=wrs -+ ;; -+ -aux*) -+ vendor=apple -+ ;; -+ -hms*) -+ vendor=hitachi -+ ;; -+ -mpw* | -macos*) -+ vendor=apple -+ ;; -+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) -+ vendor=atari -+ ;; -+ -vos*) -+ vendor=stratus -+ ;; -+ esac -+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` -+ ;; -+esac -+ -+echo $basic_machine$os -+exit -+ -+# Local variables: -+# eval: (add-hook 'write-file-hooks 'time-stamp) -+# time-stamp-start: "timestamp='" -+# time-stamp-format: "%:y-%02m-%02d" -+# time-stamp-end: "'" -+# End: ---- pmacct-0.12.1.orig/configure.in -+++ pmacct-0.12.1/configure.in -@@ -1,5 +1,5 @@ - dnl Process this file with autoconf to produce a configure script. --dnl configuration file for pmacct -+dnl configuration file for pmacct - - AC_INIT([src/pmacctd.c], [0.12.1], [paolo@pmacct.net]) - AM_INIT_AUTOMAKE([pmacctd], [0.12.1]) -@@ -108,19 +108,19 @@ dnl some systems have __progname ; if th - dnl we need to enable a minor hack to make things work nicely. - dnl - AC_MSG_CHECKING(for __progname) --AC_TRY_LINK([ extern char *__progname; ], -+AC_TRY_LINK([ extern char *__progname; ], - [ __progname = "test"; ], - [AC_MSG_RESULT(yes); AC_DEFINE(PROGNAME, 1)], [AC_MSG_RESULT(no)]) - - dnl - dnl Some checks to understand whether we need to instruct the linker for --dnl exporting collector symbols to dynamically loaded classifiers. -+dnl exporting collector symbols to dynamically loaded classifiers. - dnl - dnl OS'es with ELF executables using the GNU linker (Linux and recent *BSD, - dnl in rare cases Solaris) typically need '-Wl,-export-dynamic'; some SYSv4 - dnl systems instead need '-Wl,-Bexport'; AIX 4.x wants -Wl,-bexpall,-brtl'. - dnl -- -+ - AC_MSG_CHECKING(for extra flags needed to export symbols) - if test "x$ac_cv_prog_gcc" = xyes ; then - case $host_os in -@@ -161,9 +161,9 @@ static inline func() - [AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no); AC_DEFINE(NOINLINE, 1)]) - - dnl --dnl Check for architecture endianess: big | little -+dnl Check for architecture endianess: big | little - dnl --dnl XXX: switch to manually define this feature -+dnl XXX: switch to manually define this feature - ac_cv_endianess="unknown" - if test x"$ac_cv_endianess" = x"unknown"; then - AC_MSG_CHECKING(endianess) -@@ -250,19 +250,19 @@ AC_ARG_ENABLE(l2, - [ --disable-l2 disable Layer-2 features and support], - if test x$enableval = x"yes" ; then - AC_MSG_RESULT(no) -- AC_DEFINE(HAVE_L2, 1) -+ AC_DEFINE(HAVE_L2, 1) - else - AC_MSG_RESULT(yes) - fi - , - AC_MSG_RESULT(no) -- AC_DEFINE(HAVE_L2, 1) -+ AC_DEFINE(HAVE_L2, 1) - ) - - AC_MSG_CHECKING([whether to enable IPv6 code]) - AC_ARG_ENABLE(ipv6, - [ --enable-ipv6 Enable IPv6 code], -- [ -+ [ - AC_MSG_RESULT(yes) - AC_CHECK_FUNCS(inet_pton) - if test x"$ac_cv_func_inet_pton" = x"no"; then -@@ -285,11 +285,11 @@ AC_ARG_ENABLE(ipv6, - ipv6support="no" - ) - --if test $ipv6support = "yes"; then -+if test $ipv6support = "yes"; then - AC_MSG_CHECKING([whether to enable IPv4-mapped IPv6 sockets ]) --AC_ARG_ENABLE(v4-mapped, -+AC_ARG_ENABLE(v4-mapped, - [ --enable-v4-mapped allow IPv6 sockets to handle IPv4 connections], -- [ -+ [ - if test x$enableval = x"yes" ; then - AC_DEFINE(V4_MAPPED, 1) - AC_MSG_RESULT(yes) -@@ -320,12 +320,12 @@ AC_ARG_WITH(pcap-includes, - - if test x"$PCAPINCLS" != x""; then - AC_MSG_CHECKING(your own pcap includes) -- if test -r $PCAPINCLS/pcap.h; then -+ if test -r $PCAPINCLS/pcap.h; then - AC_MSG_RESULT(ok) - AC_DEFINE(HAVE_PCAP_H, 1) - else - AC_MSG_RESULT(no) -- AC_MSG_ERROR(ERROR: missing pcap.h in $PCAPINCLS) -+ AC_MSG_ERROR(ERROR: missing pcap.h in $PCAPINCLS) - fi - fi - -@@ -343,7 +343,7 @@ if test x"$PCAPINCLUDESFOUND" = x""; the - AC_MSG_RESULT([found in /usr/local/include]) - INCLUDES="${INCLUDES} -I/usr/local/include" - PCAPINCLUDESFOUND=1 -- AC_DEFINE(HAVE_PCAP_H, 1) -+ AC_DEFINE(HAVE_PCAP_H, 1) - elif test -r /usr/local/include/pcap/pcap.h; then - AC_MSG_RESULT([found in /usr/local/include]) - INCLUDES="${INCLUDES} -I/usr/local/include" -@@ -358,7 +358,7 @@ fi - - AC_ARG_WITH(pcap-libs, - [ --with-pcap-libs=DIR Search the specified directories for libraries], -- [ -+ [ - AC_LINEARIZE_PATH($withval, withval=$absdir) - LIBS="${LIBS} -L$withval" - PCAPLIB=$withval -@@ -467,7 +467,7 @@ AC_ARG_ENABLE(mysql, - LIBS="${LIBS} -L$withval" - MYSQLLIB=$withval - MYSQLLIBFOUND=1 -- ]) -+ ]) - - if test x"$MYSQLLIB" != x""; then - AC_MSG_CHECKING(your own MySQL client library) -@@ -493,7 +493,7 @@ AC_ARG_ENABLE(mysql, - LIBS="${LIBS} -L/usr/local/lib/mysql" - AC_MSG_RESULT([found in /usr/local/lib/mysql]) - MYSQLLIBFOUND=1 -- else -+ else - AC_MSG_RESULT([not found]) - fi - fi -@@ -502,7 +502,7 @@ AC_ARG_ENABLE(mysql, - AC_CHECK_LIB([mysqlclient], [mysql_real_connect], [], [AC_MSG_ERROR([ - ERROR: missing MySQL client library. Refer to: http://www.mysql.com/ - ])]) -- else -+ else - LIBS="${LIBS} -lmysqlclient" - case "$host_os" in - Sun*) -@@ -533,7 +533,7 @@ AC_ARG_ENABLE(mysql, - fi - fi - -- if test x"$MYSQLINCLUDESFOUND" = x""; then -+ if test x"$MYSQLINCLUDESFOUND" = x""; then - AC_MSG_CHECKING([default locations for mysql.h]) - if test -r /usr/include/mysql/mysql.h; then - AC_MSG_RESULT([found in /usr/include/mysql]) -@@ -555,12 +555,12 @@ AC_ARG_ENABLE(mysql, - - if test x"$MYSQLINCLUDESFOUND" = x""; then - AC_CHECK_HEADER([mysql/mysql.h],, -- [AC_MSG_ERROR(ERROR: missing MySQL headers)]) -+ [AC_MSG_ERROR(ERROR: missing MySQL headers)]) - fi - - AC_DEFINE(WITH_MYSQL, 1) - PLUGINS="${PLUGINS} mysql_plugin.c" -- EXTRABIN="${EXTRABIN} pmmyplay" -+ EXTRABIN="${EXTRABIN} pmmyplay" - ;; - no) - AC_MSG_RESULT(no) -@@ -585,7 +585,7 @@ AC_ARG_ENABLE(pgsql, - LIBS="${LIBS} -L$withval" - PGSQLLIB=$withval - PGSQLLIBFOUND=1 -- ]) -+ ]) - - if test x"$PGSQLLIB" != x""; then - AC_MSG_CHECKING(your own PostgreSQL client library) -@@ -610,7 +610,7 @@ AC_ARG_ENABLE(pgsql, - LIBS="${LIBS} -L/usr/local/pgsql/lib" - AC_MSG_RESULT([found in /usr/local/pgsql/lib]) - PGSQLLIBFOUND=1 -- else -+ else - AC_MSG_RESULT([not found]) - fi - fi -@@ -619,9 +619,9 @@ AC_ARG_ENABLE(pgsql, - AC_CHECK_LIB([pq], [PQconnectdb], [], [AC_MSG_ERROR([ - ERROR: missing PQ library. Refer to: http://www.postgresql.org/ - ])]) -- else -+ else - LIBS="${LIBS} -lpq" -- fi -+ fi - - AC_ARG_WITH(pgsql-includes, - [ --with-pgsql-includes=DIR Search for PostgreSQL includes in the specified directory], -@@ -642,7 +642,7 @@ AC_ARG_ENABLE(pgsql, - fi - fi - -- if test x"$PGSQLINCLUDESFOUND" = x""; then -+ if test x"$PGSQLINCLUDESFOUND" = x""; then - AC_MSG_CHECKING([default locations for libpq-fe.h]) - if test -r /usr/include/libpq-fe.h; then - AC_MSG_RESULT([found in /usr/include]) -@@ -663,12 +663,12 @@ AC_ARG_ENABLE(pgsql, - - if test x"$PGSQLINCLUDESFOUND" = x""; then - AC_CHECK_HEADER([libpq-fe.h],, -- [AC_MSG_ERROR(ERROR: missing PostgreSQL headers)]) -+ [AC_MSG_ERROR(ERROR: missing PostgreSQL headers)]) - fi - - AC_DEFINE(WITH_PGSQL, 1) - PLUGINS="${PLUGINS} pgsql_plugin.c" -- EXTRABIN="${EXTRABIN} pmpgplay" -+ EXTRABIN="${EXTRABIN} pmpgplay" - ;; - no) - AC_MSG_RESULT(no) -@@ -692,7 +692,7 @@ AC_ARG_ENABLE(sqlite3, - LIBS="${LIBS} -L$withval" - SQLITE3LIB=$withval - SQLITE3LIBFOUND=1 -- ]) -+ ]) - - if test x"$SQLITE3LIB" != x""; then - AC_MSG_CHECKING(your own SQLite3 client library) -@@ -718,7 +718,7 @@ AC_ARG_ENABLE(sqlite3, - LIBS="${LIBS} -L/usr/local/lib" - AC_MSG_RESULT([found in /usr/local/lib]) - SQLITE3LIBFOUND=1 -- else -+ else - AC_MSG_RESULT([not found]) - fi - fi -@@ -727,9 +727,9 @@ AC_ARG_ENABLE(sqlite3, - AC_CHECK_LIB([sqlite3], [sqlite3_open], [], [AC_MSG_ERROR([ - ERROR: missing SQLite3 client library. Refer to: http://sqlite.org/ - ])]) -- else -+ else - LIBS="${LIBS} -lsqlite3" -- fi -+ fi - - AC_ARG_WITH(sqlite3-includes, - [ --with-sqlite3-includes=DIR Search for SQLite3 includes in the specified directory], -@@ -750,7 +750,7 @@ AC_ARG_ENABLE(sqlite3, - fi - fi - -- if test x"$SQLITE3INCLUDESFOUND" = x""; then -+ if test x"$SQLITE3INCLUDESFOUND" = x""; then - AC_MSG_CHECKING([default locations for sqlite3.h]) - if test -r /usr/include/sqlite3.h; then - AC_MSG_RESULT([found in /usr/include]) -@@ -771,7 +771,7 @@ AC_ARG_ENABLE(sqlite3, - - if test x"$SQLITE3INCLUDESFOUND" = x""; then - AC_CHECK_HEADER([sqlite3.h],, -- [AC_MSG_ERROR(ERROR: missing SQLite3 headers)]) -+ [AC_MSG_ERROR(ERROR: missing SQLite3 headers)]) - fi - - AC_DEFINE(WITH_SQLITE3, 1) -@@ -789,12 +789,12 @@ AC_ARG_ENABLE(so, - [ --disable-so Disable shared objects], - if test x$enableval = x"yes" ; then - AC_MSG_RESULT(no) -- AC_CHECK_FUNC(dlopen, [ USING_DLOPEN="yes" ], []) -- if test x"$USING_DLOPEN" != x"yes"; then -+ AC_CHECK_FUNC(dlopen, [ USING_DLOPEN="yes" ], []) -+ if test x"$USING_DLOPEN" != x"yes"; then - AC_CHECK_LIB(dl, dlopen, - [ USING_DLOPEN="yes" - LIBS="${LIBS} -ldl" ], -- [ AC_MSG_ERROR(Unable to find dlopen(). Try with --disable-so) ]) -+ [ AC_MSG_ERROR(Unable to find dlopen(). Try with --disable-so) ]) - fi - else - AC_MSG_RESULT(yes) -@@ -817,7 +817,7 @@ fi - - if test x"$USING_SQL" = x"yes"; then - PLUGINS="${PLUGINS} sql_common.c sql_handlers.c log_templates.c preprocess.c" -- LIBS="${LIBS} -lm -lz" -+ LIBS="${LIBS}" - fi - - dnl Checks for header files. -@@ -854,7 +854,7 @@ AC_ARG_ENABLE(threads, - if test x$enableval = x"yes" ; then - AC_MSG_RESULT(yes) - AC_DEFINE(ENABLE_THREADS, 1) -- -+ - dnl OS Specifics - [ - case "$host" in -@@ -896,7 +896,7 @@ dnl AC_CHECK_FUNCS(inet_ntoa socket) - AC_CHECK_FUNCS([strlcpy vsnprintf setproctitle]) - - dnl final checks --dnl trivial solution to portability issue -+dnl trivial solution to portability issue - CFLAGS="${CFLAGS} ${INCLUDES}" - INCLUDES="" - diff -Nru pmacct-0.12.1/debian/patches/series pmacct-0.12.5/debian/patches/series --- pmacct-0.12.1/debian/patches/series 2010-04-08 11:46:37.000000000 +0000 +++ pmacct-0.12.5/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -debian-changes-0.12.1-1 diff -Nru pmacct-0.12.1/debian/pmacct.1 pmacct-0.12.5/debian/pmacct.1 --- pmacct-0.12.1/debian/pmacct.1 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.1 2012-02-10 02:36:19.000000000 +0000 @@ -0,0 +1,121 @@ +.\" Initial compilation manufacture around midnight +.\" at the end of March 10th, 2011. + +.TH "pmacct" "1" "March 2011" "0.12.1" "pmacct" +.SH NAME +pmacct \- frontend to pmacctd. +.SH SYNOPSIS +.B pmacct +\fIquery\fR +.SH DESCRIPTION +.B pmacct +is a frontend to +.BR pmacctd (8) +when used in volatile memory mode. +.PP +The type of query is specified using options. +At least one of the options +\fB\-C\fR, \fB\-c\fR, \fB\-e\fR, \fB\-s\fR, or \fB\-t\fR +is mandatory, but with \fB\-c\fR either of \fB\-M\fR or +\fB\-N\fR must be used for further specification. + +.SH OPTIONS +For displaying data either of these options are used: +.TP +\fB\-s\fR +Show full statistics. +.TP +\fB\-c \fI aggregate\fR +Specify primitives in a match aggregation, in order to present +partial statistics. Either \fB\-M\fR or \fB\-N\fR must be used +to specify matching data for this option. Here \fI aggregate\fR +is a comma separated string constructed from the following +identifiers, in arbitrary order: + +src_mac, dst_mac, vlan, src_host, dst_host, src_net, dst_net, +src_mask, dst_mask, src_port, dst_port, tos, proto, src_as, +dst_as, sum_mac, sum_host, sum_net, sum_as, sum_port, in_iface, +out_iface, tag, tag2, flows, class, std_comm, ext_comm, as_path, +peer_src_ip, peer_dst_ip, peer_src_as, peer_dst_as, src_as_path, +src_std_comm, src_med, src_ext_comm, src_local_pref, is_symmetric. + +Only entries which match the aggregate are printed. +.PP +Management of the server daemon is offered by three options: + +.TP +\fB\-e\fR +Clear all statistics. For a partial clear, see \fB\-r\fR. +.TP +\fB\-t\fR +Show memory table status. +.TP +\fB\-C\fR +Show a table of all active classifiers. + +.SH MODIFIERS +The primary options above can be influenced by some secondary options: +.TP +\fB\-p \fR \fI file\fR +Unix socket location for client\-server communication. Default is +\fI/tmp/collect.pipe\fR. +.TP +\fB\-a\fR +Display all table fields, even currently unused fields. +.TP +\fB\-S\fR +Calculate a summed total of all counters, instead of returning +a counter for each individual match; applies to \fB\-N\fR. +.TP +\fB\-n\fR {bytes|packets|flows|all} +Select which counters to print. This applies only to \fB\-N\fR. +.TP +\fB\-T\fR {bytes|packets|flows} +Output statistics ordered by decreasing value of the indicated field. +This option applies to \fB\-M\fR and to \fB\-s\fR. +.TP +\fB\-r\fR +Reset counters in the present selection after printing their values. +The option applies only to \fB\-M\fR and to \fB\-N\fR. +.TP +\fB\-l\fR +Perform a locking on the table. + +.TP +\fB\-M\fR {\fImatch_data\fR | file:\fIfilename\fR} +Print a formatted table for all entries matching the given data. +An aggregation must be specified using \fB\-c\fR, and the field +order given there must be observed when stating the data here. +The output can be influenced using \fB\-T\fR. +.IP +Here \fImatch_data\fR is a number of substrings separated by +semicolon, each substring being a comma separated list of acceptable +values in a match aggregation. A wildcard \'*\' can be used +to match any value in a specific field. +.IP +As an alternative, a location \fIfilename\fR of a file can be +specified. This file provides the substrings mentioned above +as separate lines. The prefix \'file:\' is a verbatim marker. + +.TP +\fB\-N \fI {\fImatch_data\fR | file:\fIfilename\fT} +Print counters only, no text fields, header, or footer. +This presupposes \fB\-c\fR, and can be influenced by \fB\-n\fR +and \fB\-S\fR. The arguments are identical to those for \fB\-M\fR. + +.SH EXAMPLES +The file +.I /usr/share/doc/pmacct/EXAMPLES.gz +contains suggestions prepared by the upstream author. + +.PP +For suggestions, critisism, and bugs, get in contact with +Paolo Lucente . + +.SH "SEE ALSO" +.BR pmacctd (8) + +.SH AUTHOR +This text was originally compiled by Mats Erik Andersson +for the Debian project, but may be distributed for other +uses under the same licensing as the software itself. diff -Nru pmacct-0.12.1/debian/pmacctd.conf pmacct-0.12.5/debian/pmacctd.conf --- pmacct-0.12.1/debian/pmacctd.conf 2010-04-08 11:46:27.000000000 +0000 +++ pmacct-0.12.5/debian/pmacctd.conf 2012-02-14 06:41:09.000000000 +0000 @@ -26,4 +26,4 @@ ! create new rows on the minute, hour, day boundaries !sql_history_roundoff: mhd ! in case of emergency, log to this file -!sql_recovery_logfile: /var/lib/pmacct/recovery_log +!sql_recovery_logfile: /var/lib/pmacct/pmacctd_recovery_log diff -Nru pmacct-0.12.1/debian/pmacct.init pmacct-0.12.5/debian/pmacct.init --- pmacct-0.12.1/debian/pmacct.init 2010-04-08 11:46:27.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.init 2012-02-14 07:16:00.000000000 +0000 @@ -2,8 +2,8 @@ ### BEGIN INIT INFO # Provides: pmacct -# Required-start: $network $syslog $remote_fs -# Required-stop: $network $syslog $remote_fs +# Required-start: $network $syslog +# Required-stop: $network $syslog # Default-start: 2 3 4 5 # Default-stop: 0 1 6 # Short-Description: promiscuous mode accounting daemon @@ -26,7 +26,7 @@ #start-stop-daemon --stop --oknodo --quiet \ # --pidfile /var/run/$NAME.pid \ # --exec $DAEMON - killall -INT pmacctd + killall -TERM pmacctd } start () { @@ -35,7 +35,7 @@ # --exec $DAEMON -- -f $PMACCTD_CONF $DAEMON_OPTS if [ -n "$INTERFACES" ]; then for i in $INTERFACES; do - ip link set $i up + ifconfig $i up $DAEMON -f $CONFDIR/pmacctd.$i.conf $DAEMON_OPTS done else diff -Nru pmacct-0.12.1/debian/pmacct.manpages pmacct-0.12.5/debian/pmacct.manpages --- pmacct-0.12.1/debian/pmacct.manpages 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.manpages 2012-02-10 02:42:01.000000000 +0000 @@ -0,0 +1 @@ +debian/pmacct.1 diff -Nru pmacct-0.12.1/debian/pmacct.nfacctd.default pmacct-0.12.5/debian/pmacct.nfacctd.default --- pmacct-0.12.1/debian/pmacct.nfacctd.default 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.nfacctd.default 2012-02-14 06:40:50.000000000 +0000 @@ -0,0 +1,17 @@ +# Defaults for nfacct initscript +# sourced by /etc/init.d/nfacct +# installed at /etc/default/sfacct by the maintainer scripts + +# +# This is a POSIX shell fragment +# + +# Location of the configuration file +NFACCTD_CONF=/etc/pmacct/nfacctd.conf + +# List of interfaces to start accounting on. +# See /usr/share/doc/pmacct/README.Debian for details. +INTERFACES="" + +# Additional options that are passed to nfacctd +DAEMON_OPTS="" diff -Nru pmacct-0.12.1/debian/pmacct.nfacctd.init pmacct-0.12.5/debian/pmacct.nfacctd.init --- pmacct-0.12.1/debian/pmacct.nfacctd.init 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.nfacctd.init 2012-02-14 07:16:00.000000000 +0000 @@ -0,0 +1,89 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: nfacct +# Required-start: $network $syslog +# Required-stop: $network $syslog +# Default-start: 2 3 4 5 +# Default-stop: 0 1 6 +# Short-Description: netflow accounting daemon +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/nfacctd +NAME=nfacctd +DESC="netflow accounting daemon" +CONFDIR=/etc/pmacct + +test -x $DAEMON || exit 0 + +# Include nfacct defaults if available +if [ -f /etc/default/nfacctd ] ; then + . /etc/default/nfacctd +fi + +stop () { + #start-stop-daemon --stop --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON + killall -TERM nfacctd +} + +start () { + #start-stop-daemon --start --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON -- -f $PMACCTD_CONF $DAEMON_OPTS + if [ -n "$INTERFACES" ]; then + for i in $INTERFACES; do + ip link set $i up + $DAEMON -f $CONFDIR/nfacctd.$i.conf $DAEMON_OPTS + done + else + $DAEMON -f $CONFDIR/nfacctd.conf $DAEMON_OPTS + fi +} + +case "$1" in + start) + echo -n "Starting $DESC: " + start + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + stop + echo "$NAME." + ;; + #reload) + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + # echo "Reloading $DESC configuration files." + # start-stop-daemon --stop --signal 1 --quiet --pidfile \ + # /var/run/$NAME.pid --exec $DAEMON + #;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + stop + sleep 1 + start + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff -Nru pmacct-0.12.1/debian/pmacct.sfacctd.default pmacct-0.12.5/debian/pmacct.sfacctd.default --- pmacct-0.12.1/debian/pmacct.sfacctd.default 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.sfacctd.default 2012-02-14 06:40:50.000000000 +0000 @@ -0,0 +1,17 @@ +# Defaults for sfacct initscript +# sourced by /etc/init.d/sfacct +# installed at /etc/default/sfacct by the maintainer scripts + +# +# This is a POSIX shell fragment +# + +# Location of the configuration file +SFACCTD_CONF=/etc/pmacct/sfacctd.conf + +# List of interfaces to start accounting on. +# See /usr/share/doc/pmacct/README.Debian for details. +INTERFACES="" + +# Additional options that are passed to sfacctd +DAEMON_OPTS="" diff -Nru pmacct-0.12.1/debian/pmacct.sfacctd.init pmacct-0.12.5/debian/pmacct.sfacctd.init --- pmacct-0.12.1/debian/pmacct.sfacctd.init 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.sfacctd.init 2012-02-14 07:16:00.000000000 +0000 @@ -0,0 +1,89 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: sfacct +# Required-start: $network $syslog +# Required-stop: $network $syslog +# Default-start: 2 3 4 5 +# Default-stop: 0 1 6 +# Short-Description: sflow accounting daemon +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/sfacctd +NAME=sfacctd +DESC="sflow accounting daemon" +CONFDIR=/etc/pmacct + +test -x $DAEMON || exit 0 + +# Include sfacct defaults if available +if [ -f /etc/default/sfacctd ] ; then + . /etc/default/sfacctd +fi + +stop () { + #start-stop-daemon --stop --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON + killall -TERM sfacctd +} + +start () { + #start-stop-daemon --start --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON -- -f $PMACCTD_CONF $DAEMON_OPTS + if [ -n "$INTERFACES" ]; then + for i in $INTERFACES; do + ip link set $i up + $DAEMON -f $CONFDIR/sfacctd.$i.conf $DAEMON_OPTS + done + else + $DAEMON -f $CONFDIR/sfacctd.conf $DAEMON_OPTS + fi +} + +case "$1" in + start) + echo -n "Starting $DESC: " + start + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + stop + echo "$NAME." + ;; + #reload) + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + # echo "Reloading $DESC configuration files." + # start-stop-daemon --stop --signal 1 --quiet --pidfile \ + # /var/run/$NAME.pid --exec $DAEMON + #;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + stop + sleep 1 + start + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff -Nru pmacct-0.12.1/debian/pmacct.uacctd.default pmacct-0.12.5/debian/pmacct.uacctd.default --- pmacct-0.12.1/debian/pmacct.uacctd.default 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.uacctd.default 2012-02-14 07:01:00.000000000 +0000 @@ -0,0 +1,17 @@ +# Defaults for uacct initscript +# sourced by /etc/init.d/uacct +# installed at /etc/default/uacct by the maintainer scripts + +# +# This is a POSIX shell fragment +# + +# Location of the configuration file +PMACCTD_CONF=/etc/uacct/uacctd.conf + +# List of interfaces to start accounting on. +# See /usr/share/doc/uacct/README.Debian for details. +INTERFACES="" + +# Additional options that are passed to uacctd +DAEMON_OPTS="" diff -Nru pmacct-0.12.1/debian/pmacct.uacctd.init pmacct-0.12.5/debian/pmacct.uacctd.init --- pmacct-0.12.1/debian/pmacct.uacctd.init 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/pmacct.uacctd.init 2012-02-14 07:16:00.000000000 +0000 @@ -0,0 +1,89 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: uacct +# Required-start: $network $syslog +# Required-stop: $network $syslog +# Default-start: 2 3 4 5 +# Default-stop: 0 1 6 +# Short-Description: promiscuous mode accounting daemon +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/uacctd +NAME=uacctd +DESC="promiscuous mode accounting daemon" +CONFDIR=/etc/uacct + +test -x $DAEMON || exit 0 + +# Include uacct defaults if available +if [ -f /etc/default/uacctd ] ; then + . /etc/default/uacctd +fi + +stop () { + #start-stop-daemon --stop --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON + killall -TERM uacctd +} + +start () { + #start-stop-daemon --start --oknodo --quiet \ + # --pidfile /var/run/$NAME.pid \ + # --exec $DAEMON -- -f $PMACCTD_CONF $DAEMON_OPTS + if [ -n "$INTERFACES" ]; then + for i in $INTERFACES; do + ifconfig $i up + $DAEMON -f $CONFDIR/uacctd.$i.conf $DAEMON_OPTS + done + else + $DAEMON -f $CONFDIR/uacctd.conf $DAEMON_OPTS + fi +} + +case "$1" in + start) + echo -n "Starting $DESC: " + start + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + stop + echo "$NAME." + ;; + #reload) + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + # echo "Reloading $DESC configuration files." + # start-stop-daemon --stop --signal 1 --quiet --pidfile \ + # /var/run/$NAME.pid --exec $DAEMON + #;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + stop + sleep 1 + start + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff -Nru pmacct-0.12.1/debian/rules pmacct-0.12.5/debian/rules --- pmacct-0.12.1/debian/rules 2010-04-08 11:46:27.000000000 +0000 +++ pmacct-0.12.5/debian/rules 2012-02-14 07:08:59.000000000 +0000 @@ -39,6 +39,8 @@ --enable-mysql \ --enable-sqlite3 \ --enable-ipv6 \ + --enable-64bit \ + --enable-threads \ || cat config.log build: build-stamp @@ -69,7 +71,9 @@ dh_prep dh_installdirs $(MAKE) install DESTDIR=$(CURDIR)/debian/pmacct - cp debian/pmacctd.conf $(CURDIR)/debian/pmacct/etc/pmacct/pmacctd.conf + install -m 0600 debian/pmacctd.conf $(CURDIR)/debian/pmacct/etc/pmacct/pmacctd.conf + install -m 0600 debian/sfacctd.conf $(CURDIR)/debian/pmacct/etc/pmacct/sfacctd.conf + install -m 0600 debian/nfacctd.conf $(CURDIR)/debian/pmacct/etc/pmacct/nfacctd.conf # Build architecture-independent files here. @@ -81,7 +85,7 @@ dh_testdir dh_testroot dh_installchangelogs ChangeLog - dh_installdocs + dh_installdocs -X.arch dh_installexamples # dh_install # dh_installmenu @@ -91,6 +95,9 @@ # dh_installpam # dh_installmime dh_installinit + dh_installinit --name nfacctd --no-start + dh_installinit --name sfacctd --no-start + dh_installinit --name uacctd --no-start # dh_installcron # dh_installinfo dh_installman diff -Nru pmacct-0.12.1/debian/sfacctd.conf pmacct-0.12.5/debian/sfacctd.conf --- pmacct-0.12.1/debian/sfacctd.conf 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/sfacctd.conf 2012-02-14 06:41:09.000000000 +0000 @@ -0,0 +1,29 @@ +! sfacctd configuration +! +! +! +daemonize: true +pidfile: /var/run/sfacctd.pid +syslog: daemon +! +! interested in in and outbound traffic +aggregate: src_host,dst_host +! on this network +pcap_filter: net 127.0.0.0/8 +! on this interface +interface: lo +! +! storage methods +!plugins: pgsql +!sql_host: localhost +!sql_passwd: +! refresh the db every minute +!sql_refresh_time: 60 +! reduce the size of the insert/update clause +!sql_optimize_clauses: true +! accumulate values in each row for up to an hour +!sql_history: 1h +! create new rows on the minute, hour, day boundaries +!sql_history_roundoff: mhd +! in case of emergency, log to this file +!sql_recovery_logfile: /var/lib/pmacct/sfacctd_recovery_log diff -Nru pmacct-0.12.1/debian/source/options pmacct-0.12.5/debian/source/options --- pmacct-0.12.1/debian/source/options 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/debian/source/options 2012-02-10 02:20:06.000000000 +0000 @@ -0,0 +1,2 @@ +# Don't store changes on autogenerated files. +extend-diff-ignore = "(^|/)(config\.sub|config\.guess|Makefile|configure(\.in)?)" diff -Nru pmacct-0.12.1/docs/INTERNALS pmacct-0.12.5/docs/INTERNALS --- pmacct-0.12.1/docs/INTERNALS 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/docs/INTERNALS 2010-09-09 14:35:47.000000000 +0000 @@ -1,6 +1,3 @@ -pmacct (Promiscuous mode IP Accounting package) -pmacct is Copyright (C) 2003-2006 by Paolo Lucente - (poorman's) TABLE OF CONTENTS: I. Introduction II. Primitives @@ -13,6 +10,7 @@ IX. pmacctd flows counter implementation X. Classifier and connection tracking engines XI. Jumps and flow diversions in Pre-Tagging infrastructure +XII. BGP daemon thread dimensioning I. Introduction @@ -27,23 +25,21 @@ II. Primitives -Either individual packets or specific flows are identified by their header fields (which -union gives origin to a rather large set of primitives). Aggregates are identified by a -reduced set of primitives instead. Packets are merged into aggregates by stripping from -the original set of primitives those not used in the reduced set and then summing their -referred counters (bytes and packets). Additional operations involved into the merging -process include the logical grouping of specific primitives into more general entities -(IP addresses into network prefixes, for example) and tagging of packets. -While looking forward, we already have a more generalized view of the primitives, which -will enable to bind aggregation methods to arbitrary pieces of the packet but actually -primitives already give the desired flexibility. In fact, the concept of primitive itself -carries the idea of a simple entity that could be stacked along with other primitives to -form complex expressions using boolean operators. But going practical, what are primitives ? -They are atomic expressions like "src_port", "dst_host", "proto"; currently the unique -boolean operator supported to glue expressions is "and". Hence, traffic could be aggregated -translating a "who connects where, using which service" speech language phrase into one -recognized by pmacct: "src_host,dst_host,dst_port,proto". Comma, because of the unique -logical connective "and", is simply intended as a separator. +Individual packets and specific traffic flows are identified by their header fields. +The union of such header fields generates (a rather large) set of primitives. Traffic +aggregates are typically identified by a reduced set of primitives instead. Packets +or flows are merged into aggregates by defining a sub-set of primitives, by shaving +off unused primitives from the original set and finally by summing their counters +(ie. bytes and packets). Additional operations involved into the process can also +include logical grouping of specific primitives into more general entities (ie. IP +addresses into network prefixes), temporal aggregation (ie. splitting aggregates in +time bins), tagging, sampling and filtering. +What are primitives? They are atomic expressions ie. "src_port", "dst_host", "proto"; +currently the unique boolean operator supported to glue expressions is "and". Hence, +traffic could be aggregated translating a "who connects where, using which service" +speech language statement into one recognized by pmacct: "src_host,dst_host,dst_port, +proto". Comma, because of the unique logical connective "and", is simply intended as +a separator. III. The whole picture @@ -82,29 +78,27 @@ IV. Processes Vs. threads -pmacctd, nfacctd and sfacctd, the pmacct package daemons, rely strongly over a multi-process -organization rather than over threads. For threads we mean what is commonly referred as -threads of execution that share their entire address space inside a single process. -Processes are used to encapsulate each plugin instance and, indeed, the Core Process. It -either captures packets via the well-known libpcap API (pmacctd) or listens for specific -packets coming from the network (nfacctd, for example, listens for NetFlow packets); packets -are then processed (filtered out, tagged, aggregated and bufferized) and sent to the active -plugins. They pick and handle in some meaningful way aggregated data (struct pkt_data). -A picture follows: +pmacctd, nfacctd and sfacctd, the pmacct package daemons, rely over both a multi-thread +and multi-process architecture. Processes are used to encapsulate each plugin instance +and, indeed, the Core Process. Threads are used to encapsulate specific functions within +each process - ie. the BGP daemon thread within the Core Process. +The Core Process either captures packets via the well-known libpcap API (pmacctd) or +listens for specific packets coming from the network (nfacctd, for example, listens +for NetFlow packets); packets are then processed (parsed, filtered, sampled, tagged, +aggregated and bufferized if required) and sent to the active plugins. Plugins in +turn pick and handle in some meaningful way aggregated data (struct pkt_data), ie. +writing them to a SQL database, a memory table, etc. A diagram follows: + |===> [ pmacctd/plugin ] libpcap pipe/shm| ===========> [ pmacctd/core ]==============|===> [ pmacctd/plugin ] socket -I don't like, except for specific cases (eg. big memory structures that would lead the -pages' copy-on-write to perform horrendly), the idea of threads on UNIXes and Linux. They -are suitable and are born in environments with expensive process spawning and weak IPC -facilities. Moreover the task of managing critical regions in a shared address space is -sometimes a fertile source of bugs simply because they easily know too much about each -others' internal states. They frequently translate in adding tricky issues described in -each good Operating Systems' textbook: a fully new range of timing dependent bugs that -are excruciatingly difficult to even reproduce. These considerations leave untouched -portability troubles and differences of behaviour across platforms. +To conclude a position on threads: threads are a necessity because of the tendency +modern CPU are built (ie. multi-core). So far pmacct limits iteself to a macro-usage +of threads, ie. where it makes sense to save on IPC or where big memory structures +would lead the pages' copy-on-write to perform horrendly. The rationale is that fine- +grained multi-threading can often become a fertile source of bugs. V. Communications between core process and plugins @@ -132,31 +126,31 @@ few simple equations: dss = Default Segment Size -dbs = Default Buffer Size = sizeof(struct pkt_data) ~ 40 bytes +dbs = Default Buffer Size = sizeof(struct pkt_data) as = Address Size = sizeof(char *) (it depends upon the hardware architecture) bs = 'plugin_buffer_size' value ss = 'plugin_pipe_size' value a) no 'plugin_buffer_size' and no 'plugin_pipe_size': circular queue size = (dss / as) * dbs - signallation queue size = dss + signalling queue size = dss b) 'plugin_buffer_size' defined but no 'plugin_pipe_size': circular queue size = (dss / as) * bs - signallation queue size = dss + signalling queue size = dss c) no 'plugin_buffer_size' but 'plugin_pipe_size' defined: circular queue size = ss - signallation queue size = (ss / dbs) * as + signalling queue size = (ss / dbs) * as d) 'plugin_buffer_size' and 'plugin_pipe_size' defined: circular queue size = ss - signallation queue size = (ss / bs) * as + signalling queue size = (ss / bs) * as Intuitively, the equations above tell that if no 'plugin_pipe_size' is defined, the size -of the circular queue is inferred by the size of the signallation queue, which is selected +of the circular queue is inferred by the size of the signalling queue, which is selected by the Operating System. If 'plugin_pipe_size' is defined, the circular queue size is set -to the supplied value and the signallation queue size is adjusted accordingly. +to the supplied value and the signalling queue size is adjusted accordingly. If 'plugin_buffer_size' is not defined, it's assumed to be sizeof(struct pkt_data), which is the size of a single aggregate travelling through the circolar queue; 'sizeof(char *)' is the size of a pointer, which is architecture-dependant. @@ -181,7 +175,7 @@ | |==|==|==|==|==|==|==|===========| | | | `-------------------------------------------' - OOB signallation queue + OOB signalling queue VI. Memory table plugin @@ -245,43 +239,52 @@ VII. SQL issues and *SQL plugins -Currently two SQL plugins are available; one allows for aggregates insertion in a MySQL -DB, the other into a PostgreSQL DB. Storing aggregates into a persistent backend leaves chances for advanced operations and so these plugins are intended to give a wider range of features (eg. fallback mechanisms and backup storage methods if DB fails, counters breakdown, etc.) not available in other plugins. Let's firstly give a whole picture of how these SQL plugins work. As packets received from core process via communication channel get unpacked, they are inserted in a -direct-mapped cache; then, at fixed time intervals (configurable via 'sql_history' key) -cache is purged and aggregates are pushed into DB; optionally triggers may be selected for -execution. Data to cache bucket mapping is computed via a modulo function. If bucket already -contains valid data then a new chain is built (or traversed when it already exists); the -first free node encountered is used; if no free nodes are found then two more chances are -explored: if any node has been marked as stale (it happens when an allocated node is unused -for some consecutive timeslots) it's reused by moving it away from its old chain; if no -free nodes are available then a new one is allocated. Stale nodes are, then, retired if +direct-mapped cache; then, at fixed time intervals (configurable via 'sql_refresh_time' +key) the cache scanner kicks in and purges content to the database; optionally triggers +may be executed (sql_trigger_exec, sql_trigger_time). Data to cache bucket mapping is +computed via a modulo function. If the selected bucket already contains valid data then +a conflict chain is built (or traversed if it already exists); the first free node +encountered is used; if no free nodes are found then two more chances are explored: if +any node has been marked as stale (it happens when an allocated node is unused for some +consecutive time-bins) it is then reused by moving it away from its old chain; if no +free nodes are available then a new one is allocated. Stale nodes are then retired if they still remain unused for longer times (RETIRE_TIME**2). To speed up nodes reuse and -retirement, an additional LRU list of nodes is also mantained. -As told before, aggregates are pushed into the DB at regular intervals; to speed up such +retirement, an additional LRU list of nodes is also mantained. +If out of memory or the maximum number of allowed elements in the cache is reached data +is immediately written to the database so to make room for further elements. The maximum +number of allowed elements is defined to prevent the cache to grow in memory without any +control. Such limit is internally calculated as: + + max cache elements = sql_cache_entries + ( sql_refresh_time * 100 ) + +As said before, aggregates are pushed into the DB at regular intervals; to speed up such operation a queue of pending queries is built as nodes are used; this allows to avoid long -walks through the whole cache structure. -When current timeslot expires a new process is spawned and charged of queue processing; SQL -queries are built and sent to the DB. Because we, at this moment, don't known if INSERT queries -would create duplicates, an UPDATE query is launched first and only if no rows are affected, -then an INSERT query is trapped. 'sql_dont_try_update' reverts this default behaviour and -skips directly to INSERT queries; you must be sure there are no risks of duplicate aggregates -to avoid data loss, when enabling this configuration directive. -Data in the cache is never erased but simply marked as invalid; this way while correctess of -data is still preserved, we avoid the waste of CPU cycles. -The number of cache buckets is tunable via the 'sql_cache_entries' configuration key; a prime -number is strongly advisable to ensure a better data dispersion through the cache. -Three notes about the above described process: (a) few time ago the concept of lazy data refresh -deadlines has been introduced. Timeframes boundaries are checked without the auxilium of signals -but when new data comes in. If such data arrival rate is low, data is not kept stale into the -cache but a poll() timeout makes the wheel spin. (b) SQL plugins main loop has been kept sufficiently -fast because of any direct interaction with the DB. It only gets data, computes modulo and handles -both cache and queries queue. (c) cache has been thought to exploit a kind of temporal locality -in internet flows. A picture follows: +walks through the whole cache structure given, for various reasons (ie. classification, +sql_startup_delay) not all elements might be eligible for purging. +When the cache scanner kicks incurrent a new writer process is spawned and in charge of +processing the pending elements queue; SQL statements are built and sent to the RDBMS. +Because we, at this moment, don't known if INSERT queries would create duplicates, an +UPDATE query is launched first and only if no rows are affected, then an INSERT query +is trapped. 'sql_dont_try_update' twists this behaviour and skips directly to INSERT +queries; when enabling this configuration directive, you must be sure there are no risks +of duplicate aggregates to avoid data loss. +Data in the cache is never erased but simply marked as invalid; this way while correctess +of data is still preserved, we avoid the waste of CPU cycles. +The number of cache buckets is tunable via the 'sql_cache_entries' configuration key; a +prime number is strongly advisable to ensure a better data dispersion through the cache. +Three notes about the above described process: (a) some time ago the concept of lazy data +refresh deadlines has been introduced. Expiration of timers is checked without the aid of +UNIX signals but when new data comes in. If such data arrival rate is low, data is not +kept stale into the cache but a poll() timeout makes the wheel spin. (b) SQL plugins +main loop has been purposedly kept sufficiently fast thanks to no direct interaction +with the RDBMS: it only gets data, computes modulo and handles both cache and queries +queue. (c) cache has been thought to exploit a kind of temporal locality in internet +flows. A picture follows: |====> [ cache ] ===| pipe | | @@ -295,8 +298,8 @@ in flat tuples, without any external references. After being not full convinced about better normalized solutions aimed to satifsy an abstract concept of flexibility, we've (and here come into play the load of mails exchanged with Wim Kerkhoff) found that simple means faster. And to -let the wheel spin quickly is a key achievement, because pmacctd needs not only to insert new -records but also update existing ones, putting under heavy pressure DB when placed in busy +let the wheel spin quickly is a key achievement, because pmacct needs not only to insert new +records but also update existing ones, putting under heavy pressure RDBMS when placed in busy network environments and an high number of primitives are required. Now a pair of concluding practical notes: (a) default SQL table and its primary key are suitable for many normal usages, however unused fields will be filled by zeroes. We took this choice a long @@ -315,6 +318,11 @@ VIII. Recovery modes +Forewords: this chapter is left here for historical reasons; note that recovery modes support +has been largely discontinued. Resiliency and high-availability is left to clustering of the +RDBMS environment itself or multiple plugins, within the same collector, running in parallel +and writing to different backends. + The concept of recovery mechanism is available only in SQL plugins and is aimed to avoid data loss by taking a corrective action if the DB suffers an outage or simply becomes unresponsive. Actually, two mechanisms are supported: aggregates may be either (1) pulled into a structured @@ -431,4 +439,47 @@ and the receiver: this time you would need a 1-to-2 relationship. In this context, being able to handle 1-to-2 relationships becomes a requirement when sampling comes into play as any single sample is required to be assigned to both parties in order for the algorithms to work -correctly. Relationships 1-to->1 are precisely the aim for jeq, stack and return keys. +correctly. Relationships 1-to-1 are precisely the aim for jeq, stack and return keys. + + +XII. BGP daemon thread dimensioning +Memory structure of the BGP daemon thread can be broken down in three modules: IP prefixes, BGP +information and BGP attributes. Up to version 0.12.3 the multi-RIB nature of the BGP daemon was +achieved separating IP prefixes and BGP information on a per active BGP peer basis, while BGP +attributes were shared among all the peers. From a logical point these structures were relating +each other as follows: IP prefix -(1:1)-> BGP information -(N:1)-> BGP attributes. +Version 0.12.4 sees introduction of a memory model by which also IP prefixes are being shared +among the BGP peers - leading to consistent memory savings whenever multiple BGP peers export +full tables due to the almost total overlap of information. In this new model, structures are +relating each other as follows: IP prefix -(1:N)-> BGP information -(N:1)-> BGP attributes. The +longest match nature of IP lookups required to raise BGP peer awareness of the lookup algorithm +in order to fully support the newly established 1:N relation. +Following are some calculations that can ease memory dimensioning in order to support a certain +number of peers, num(B), each exporting the same full-routing table, T, which consists of num(P) +number of prefixes. The shared base of BGP attributes, A, is estimated in roughly 200MB. The BGP +information base, I, is also calculated. + +sz(P) = 16 (size of an IP prefix) +sz(Tn) = 48 (size of routing table node) +sz(In) = 32 (size of BGP information base node) +sz(THn) = 8 (size of routing table hash node) +T = num(P) * (sz(Tn) + sz(P) + (sz(THn) * bgp_table_peer_buckets)) +I = num(B) * num(P) * sz(In) +RIB = T + I + A + +Sizes are based on worse-case scenario, ie. 64-bit executable with support for IPv6 compiled in. +num(P) is a way to simplify calculations while retaining good accuracy; whereas higher precision +can be achieved by using union(P), which is the union of all prefixes exported by all BGP peers. +bgp_table_peer_buckets is set by default to 13 and is adviceable to keep its value to 1/10 of the +expected number of BGP peers; increasing such ratio improves lookup performances at the expense +of more sustained memory usage. +As an example, let's imagine a scenario where 500 BGP peers export the same 500K IPv4 routes and +50K IPv6 routes and bgp_table_peer_buckets is set to a value of 50: + +T = (500K+50K) * (48 + 16 + (8 * 50)) = 256MB +I = 500 * (500K+50K) * 32 = 8.8GB +A = ~200MB +RIB = 256MB + 8.8GB + 200MB = ~9.26GB + +Still, this example assumes a 64-bit executable. For an educated guess on how 32-bit executables +would look like, it's sufficient to divide by half output of the sz() functions presented above. diff -Nru pmacct-0.12.1/docs/PLUGINS pmacct-0.12.5/docs/PLUGINS --- pmacct-0.12.1/docs/PLUGINS 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/docs/PLUGINS 2010-05-03 15:55:01.000000000 +0000 @@ -1,40 +1,39 @@ PMACCTD PLUGIN WRITING HOW-TO SHORT OVERVIEW -the plugin architecture should allow people that need some kind of -their own backend, to write and implement it without knowing too -much of the core functionalities of pmacctd and other plugins. -Of course you will need to touch configure.in and Makefile.am in -order to let your plugin compile automatically via a --enable switch. -Below are listed a few steps to hook your plugin in pmacctd; pmacct -is a project extremely open to new ideas, so if you wish to contribute -your work, you are welcome. +the pmacct plugin architecture is thought to allow people that need +their own backend to implement it without knowing too much of core +collectors functionalities and independently by other plugins. +Below are listed a few steps to hook your plugin in pmacct; pmacct +is also extremely open to new ideas, so if you wish to contribute +your work, you are the most welcome. - minor hacks to configure.in script following the example of what - has been done there for mysql plugin; you can handle in the same - way other requirements such as paths for header or libraries. If - you'll handle correctly the PLUGINS variable, you will not need - to touch at all the Makefile.am script. Moreover, doing a definition - in configure.in (ex. AC_DEFINE(WITH_MYSQL, 1)) whose existence can - be checked via instructions to compiler's preprocessor is an easy - way to propagate the user configuration choices at compilation time. + has been done there for mysql plugin; same goes for requirements + like paths to headers or libraries. By making use of the PLUGINS + variable, it will not be required to touch the "src/Makefile.am" + script. Definitions in configure.in (ie. AC_DEFINE(WITH_MYSQL, 1)) + whose existence can be checked via compiler preprocessor is an + easy way to propagate user configuration choices at compilation + time. -- [OPTIONAL] If you need commandline switches, whose values need to - be passed to your plugin, you have to modify the configuration struct - (in cfg.h) and the getopt block in pmacctd.c . First change is needed - to add fields you need to carry your values; second change is needed - if you wish to support new commandline switches to supply your values. +- [OPTIONAL] If the plugin needs to take configurable values, this + can be achieved by defining configuration handlers (pmacct-data.h, + cfg_handlers.h, cfg_handlers.c) and declaring config variables to + deliver configured values to the plugin (cfg.h, struct configuration). + If command-line parameters are also required, some getopt() related + code needs to be dealt with (pmacct-defines.h and ie. pmacctd.c, + nfacctd.c, sfacctd.c and uacctd.c). + +- Define the new plugin in pmacct; this can be done by adding an + entry to the plugin_types_list[] array (pmacct-data.h). An entry + consists of two fields: an id string and a pointer to a function + to be called. The first is the string which will be used to call + the plugin from within the configuration or command-line. The + second is effectively the entry point to the plugin. -- Now, hook your plugin in pmacctd; you have to add an entry in the - plugin_types_list[] array in pmacct-data.h . An entry consists of - two fields: an id string and a pointer to a function to be called. - The first is the string you wish to write as an argument for '-P' - commandline switch or value for 'plugins' configuration key. The - second is the entry point for your plugin. - -- if you need to add configuration keys that suit your needs, you have - simply to add an entry in the dictionary[] array in pmacct-data.h . - An entry consists of two fields a key name and an handler. While the - first is intuitive, few words about the second field: once a key has - been recognized successfully by the parser, its value is handled via - a configuration handler (you find them in cfg_handlers.c). +- Develop the plugin code. One of the existing plugins can be used + as reference for popping data out of the circular buffer. Data + structures for parsing such data are defined in network.h file. + The basic layout for the main plugin loop can be grasped in the + print_plugin.c file by looking at content of the "for (;;)" loop. diff -Nru pmacct-0.12.1/docs/SIGNALS pmacct-0.12.5/docs/SIGNALS --- pmacct-0.12.1/docs/SIGNALS 2009-07-26 10:33:21.000000000 +0000 +++ pmacct-0.12.5/docs/SIGNALS 2010-06-30 11:08:04.000000000 +0000 @@ -11,7 +11,7 @@ 'syslog'). It works for all pmacctd/nfacctd/sfacctd; SIGUSR2: if 'refresh_maps' configuration directive is enabled it causes Core Process-based maps to be reloaded (ie. Pre-Tagging, BGP source peer ASN, NetFlow/sFlow agent to - BGP peer); + BGP peer, BGP MD5, etc.); SIGINT: ignored if the daemon is started in background; otherwise the signal is propagated to each running plugin (which is in turn gracefully terminated); SIGTERM: not handled (which means it follows the default behaviour for the OS) if the daemon @@ -62,3 +62,11 @@ SIGUSR2: if 'refresh_maps' configuration directive is enabled it causes the Ports and Networks maps to be reloaded; SIGINT: causes the process to exit gracefully; + +Tee process: +SIGPIPE: ignored; +SIGCHLD: ignored; +SIGHUP: inherited by Core Process; +SIGUSR1: ignored; +SIGUSR2: ignored; +SIGINT: causes the process to exit gracefully; diff -Nru pmacct-0.12.1/examples/agent_to_peer.map pmacct-0.12.5/examples/agent_to_peer.map --- pmacct-0.12.1/examples/agent_to_peer.map 2009-08-13 19:20:51.000000000 +0000 +++ pmacct-0.12.5/examples/agent_to_peer.map 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -! -! NetFlow/sFlow agent to BGP peer map -! -! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in this same -! directory. -! -! nfacctd, sfacctd: valid keys: id, ip. -! -! list of currently supported keys follow: -! -! 'id' IP address of the BGP peer -! 'ip' IP address of the sFlow/NetFlow agent -! -! A couple of straightforward examples follow. -! -id=1.2.3.4 ip=2.3.4.5 -! -! The following comes handy when compiling pmacct for IPv6; BGP peers -! are always IPv4 addresses. Whereas remote sFlow or NetFlow agents are -! likely to be intended as IPv4-mapped IPv6 addresses, if nfacctd_ip is -! not specified. -! -! id=3.4.5.6 ip=::ffff:4.5.6.7 -! -! The following maps something which isn't a Netflow/sFlow agent to the -! specified BGP peer. The only application for this lies with pmacctd. -! -! id=4.5.6.7 ip=0.0.0.0 -! diff -Nru pmacct-0.12.1/examples/agent_to_peer.map.example pmacct-0.12.5/examples/agent_to_peer.map.example --- pmacct-0.12.1/examples/agent_to_peer.map.example 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/examples/agent_to_peer.map.example 2010-11-07 15:11:11.000000000 +0000 @@ -0,0 +1,32 @@ +! +! NetFlow/sFlow agent to BGP peer map +! +! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in +! this same directory. +! +! nfacctd, sfacctd: valid keys: id, ip. +! +! list of currently supported keys follow: +! +! 'id' IPv4 address or router ID of the BGP peer +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. +! +! A couple of straightforward examples follow. +! +id=1.2.3.4 ip=2.3.4.5 +! +! The following comes handy when compiling pmacct for IPv6; BGP peers +! are always IPv4 addresses. Whereas remote sFlow or NetFlow agents are +! likely to be intended as IPv4-mapped IPv6 addresses, if nfacctd_ip is +! not specified. +! +! id=3.4.5.6 ip=::ffff:4.5.6.7 +! +! The following maps something which isn't a Netflow/sFlow agent to the +! specified BGP peer. The only application for this lies with pmacctd. +! +! id=4.5.6.7 ip=0.0.0.0 +! diff -Nru pmacct-0.12.1/examples/bgp_md5.lst.example pmacct-0.12.5/examples/bgp_md5.lst.example --- pmacct-0.12.1/examples/bgp_md5.lst.example 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/examples/bgp_md5.lst.example 2010-06-25 16:48:05.000000000 +0000 @@ -0,0 +1,8 @@ +! +! Sample BGP MD5 map; enabled by 'bgp_daemon_md5_file' key. +! +! Format supported: , +! +192.168.1.1, arealsmartpwd +192.168.1.2, TestTest +! ... diff -Nru pmacct-0.12.1/examples/is_symmetric.map.example pmacct-0.12.5/examples/is_symmetric.map.example --- pmacct-0.12.1/examples/is_symmetric.map.example 2009-12-29 00:15:36.000000000 +0000 +++ pmacct-0.12.5/examples/is_symmetric.map.example 2010-05-16 10:24:39.000000000 +0000 @@ -1,28 +1,31 @@ ! ! is_symmetric map - asymmetric traffic detection ! -! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in this same -! directory. +! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in +! this same directory. ! ! nfacctd, sfacctd: valid keys: id, ip, in, bgp_nexthop, src_mac. ! ! list of currently supported keys follow: ! -! 'id' ID value to assign to a matching packet or flow. The only valid -! value for this map is '1': underlying logics is to define via -! this map local traffic paths out of the routing domain at edge -! devices. -! 'ip' IP address of the device which is originating sFlow or NetFlow -! datagrams (router, probe, etc.) +! 'id' ID value to assign to a matching packet or flow. The +! only valid value for this map is '1': rationale is to +! manually define via this map valid traffic paths out +! of the routing domain. +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. ! 'in' Input interface -! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). This value -! is compared against the BGP RIB of the device originating the sFlow -! or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address (RPF-like). -! This value is compared against the BGP RIB of the device originating -! the sFlow or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or sFlow as -! NetFlow v5 lacks of such support. +! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). +! This value is compared against the corresponding BGP +! RIB of the exporting device. +! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address +! (RPF-like). This value is compared against the BGP RIB +! of the exporting device (see 'bgp_daemon' configuration +! directive). +! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or +! sFlow. ! ! A few examples follow. ! diff -Nru pmacct-0.12.1/examples/lpref.map.example pmacct-0.12.5/examples/lpref.map.example --- pmacct-0.12.1/examples/lpref.map.example 2009-12-29 00:15:36.000000000 +0000 +++ pmacct-0.12.5/examples/lpref.map.example 2010-05-16 10:24:39.000000000 +0000 @@ -1,28 +1,30 @@ ! ! BGP source local preferecence map ! -! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in this same -! directory. +! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in +! this same directory. ! ! nfacctd, sfacctd: valid keys: id, ip, in, bgp_nexthop, src_mac. ! ! list of currently supported keys follow: ! -! 'id' ID value to assign to a matching packet or flow. Other than local -! preference values, this field accepts also the 'bgp' keyword which -! triggers a BGP lookup and returns its result: useful to handle -! exceptions. -! 'ip' IP address of the device which is originating sFlow or NetFlow -! datagrams (router, probe, etc.) -! 'in' Input interface -! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). This value -! is compared against the BGP RIB of the device originating the sFlow -! or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address (RPF-like). -! This value is compared against the BGP RIB of the device originating -! the sFlow or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or sFlow as -! NetFlow v5 lacks of such support. +! 'id' ID value to assign to a matching packet or flow. Other +! than hard-coded local preference values, this field also +! accepts the 'bgp' keyword which triggers a BGP lookup +! and returns its result: useful to handle exceptions. +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. +! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). +! This value is compared against the corresponding BGP +! RIB of the exporting device. +! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address +! (RPF-like). This value is compared against the BGP RIB +! of the exporting device (see 'bgp_daemon' configuration +! directive). +! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or +! sFlow. ! ! A few examples follow. Let's define: LP=100 identifies customers, LP=80 identifies peers ! and LP=50 identifies IP transit. diff -Nru pmacct-0.12.1/examples/med.map.example pmacct-0.12.5/examples/med.map.example --- pmacct-0.12.1/examples/med.map.example 2009-12-27 01:10:54.000000000 +0000 +++ pmacct-0.12.5/examples/med.map.example 2010-05-16 10:24:39.000000000 +0000 @@ -1,27 +1,30 @@ ! ! BGP source MED (Multi Exit Discriminator) map ! -! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in this same -! directory. +! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in +! this same directory. ! ! nfacctd, sfacctd: valid keys: id, ip, in, bgp_nexthop, src_mac. ! ! list of currently supported keys follow: ! -! 'id' ID value to assign to a matching packet or flow. Other than MED -! values, this field accepts also the 'bgp' keyword which triggers -! a BGP lookup and returns its result: useful to handle exceptions. -! 'ip' IP address of the device which is originating sFlow or NetFlow -! datagrams (router, probe, etc.) -! 'in' Input interface -! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). This value -! is compared against the BGP RIB of the device originating the sFlow -! or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address (RPF-like). -! This value is compared against the BGP RIB of the device originating -! the sFlow or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or sFlow as -! NetFlow v5 lacks of such support. +! 'id' ID value to assign to a matching packet or flow. Other +! than hard-coded MED values this field accepts also the +! 'bgp' keyword which triggers a BGP lookup and returns +! its result: useful to handle exceptions. +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. +! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). +! This value is compared against the corresponding BGP +! RIB of the exporting device. +! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address +! (RPF-like). This value is compared against the BGP RIB +! of the exporting device (see 'bgp_daemon' configuration +! directive). +! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or +! sFlow. ! ! A few examples follow. ! diff -Nru pmacct-0.12.1/examples/peers.map.example pmacct-0.12.5/examples/peers.map.example --- pmacct-0.12.1/examples/peers.map.example 2009-12-29 00:15:36.000000000 +0000 +++ pmacct-0.12.5/examples/peers.map.example 2010-05-16 10:24:39.000000000 +0000 @@ -1,27 +1,30 @@ ! ! BGP source peer ASN map ! -! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in this same -! directory. +! File syntax is key-based. Read full syntax rules in 'pretag.map.example' in +! this same directory. ! ! nfacctd, sfacctd: valid keys: id, ip, in, bgp_nexthop, src_mac. ! ! list of currently supported keys follow: ! -! 'id' ID value to assign to a matching packet or flow. Other than AS -! numbers, this field accepts also the 'bgp' keyword which triggers -! a BGP lookup and returns its result: useful to handle exceptions. -! 'ip' IP address of the device which is originating sFlow or NetFlow -! datagrams (router, probe, etc.) -! 'in' Input interface -! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). This value -! is compared against the BGP RIB of the device originating the sFlow -! or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address (RPF-like). -! This value is compared against the BGP RIB of the device originating -! the sFlow or NetFlow datagram (see 'nfacctd_bgp' directive). -! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or sFlow as -! NetFlow v5 lacks of such support. +! 'id' ID value to assign to a matching packet or flow. Other +! than hard-coded AS numbers, this field accepts also the +! 'bgp' keyword which triggers a BGP lookup and returns +! its result: useful to handle exceptions. +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. +! 'bgp_nexthop' BGP next-hop of the flow source IP address (RPF-like). +! This value is compared against the corresponding BGP +! RIB of the exporting device. +! 'peer_dst_as' First AS hop within the AS-PATH of the source IP address +! (RPF-like). This value is compared against the BGP RIB +! of the exporting device (see 'bgp_daemon' configuration +! directive). +! 'src_mac' Source MAC address of the flow. Requires NetFlow v9 or +! sFlow. ! ! A few examples follow. ! diff -Nru pmacct-0.12.1/examples/pretag.map.example pmacct-0.12.5/examples/pretag.map.example --- pmacct-0.12.1/examples/pretag.map.example 2010-01-29 18:02:58.000000000 +0000 +++ pmacct-0.12.5/examples/pretag.map.example 2010-07-20 19:44:55.000000000 +0000 @@ -1,116 +1,140 @@ ! ! Pre-Tagging map -- multiplexes various fields into a 4-bytes numerical-only ID ! -! File syntax is key-based. Position of keys inside the same row (rule) is not relevant; -! Spaces are not allowed (ie. 'id = 1' is not valid). The first full match wins (like in -! firewall rules). Negative values mean negations (ie. match data NOT entering interface -! 2: 'in=-2'); 'id', 'id2', 'ip' and 'filter' keys don't support negative values. 'label', -! 'jeq', 'return' and 'stack' keys can be used to alter the standard rule evaluation flow. -! -! nfacctd: valid keys: id, id2, ip, in, out, engine_type, engine_id, nexthop, bgp_nexthop, -! src_as, dst_as, peer_src_as, peer_dst_as, v8agg and filter; mandatory keys for each -! rule: id or id2 and ip. -! -! sfacctd: valid keys: id, id2, ip, in, out, agent_id, nexthop, bgp_nexthop, src_as, -! dst_as, sampling_rate and filter; mandatory keys for each rule: id or id2 and ip. -! -! pmacctd: valid keys: id, id2, src_as, dst_as and filter. Only either id or id2 are -! mandatory for each rule. -! -! list of currently supported keys follow: -! -! 'id' tag assigned to a matching packet, flow or sample; its use is -! mutually exclusive with id2. The resulting label is written to -! the 'tag' field when using memory tables and 'agent_id' when -! using a SQL plugin. -! 'id2' tag assigned to a matching packet, flow or sample; its use is -! mutually exclusive with id. The resulting label is written to -! the 'tag2' field when using memory tables and 'agent_id2' when -! using a SQL plugin. If using a SQL plugin, read more about the -! 'agent_id2' field in the 'sql/README.agent_id2' document. -! 'ip' IP address of the device which is originating sFlow or NetFlow -! datagrams (router, probe, etc.) +! File syntax is key-based. Position of keys inside the same row (rule) is not +! relevant; Spaces are not allowed (ie. 'id = 1' is not valid). The first full +! match wins (like in firewall rules). Negative values mean negations (ie. match +! data NOT entering interface 2: 'in=-2'); 'id', 'id2', 'ip' and 'filter' keys +! don't support negative values. 'label', 'jeq', 'return' and 'stack' keys can +! be used to alter the standard rule evaluation flow. +! +! nfacctd: valid keys: id, id2, ip, in, out, engine_type, engine_id, nexthop, +! bgp_nexthop, src_as, dst_as, direction, v8agg, sampling_rate and filter; +! mandatory keys for each rule: id or id2 and ip. +! +! sfacctd: valid keys: id, id2, ip, in, out, agent_id, nexthop, bgp_nexthop, +! src_as, dst_as, sampling_rate and filter; mandatory keys for each rule: id or +! id2 and ip. +! +! pmacctd: valid keys: id, id2, src_as, dst_as and filter. Only either id or id2 +! are mandatory for each rule. +! +! sfacctd, nfacctd when in 'tee' mode: valid keys: id, id2, ip; mandatory keys +! for each rule: id or id2 and ip. +! +! BGP-related keys are independent of the collection method in use, hence apply +! to all daemons (BGP daemon must be enabled): src_as, dst_as, src_comms, comms, +! peer_src_as, peer_dst_as, src_local_pref, local_pref. +! +! list of currently supported keys follows: +! +! 'id' tag assigned to a matching packet, flow or sample; its +! use is mutually exclusive with id2. The resulting label +! is written to the 'tag' field when using memory tables +! and 'agent_id' when using a SQL plugin. +! 'id2' tag assigned to a matching packet, flow or sample; its +! use within a rule is mutually exclusive with 'id'. The +! resulting label is written to the 'tag2' field when +! using memory tables and 'agent_id2' when using a SQL +! plugin. If using a SQL plugin, read more about the +! 'agent_id2' field in the 'sql/README.agent_id2' document +! 'ip' In nfacctd it's compared against the source IP address +! of the device which is originating NetFlow packets; in +! sfacctd this is compared against the AgentId field of +! received sFlow samples. ! 'in' Input interface ! 'out' Output interface -! 'engine_type' In NetFlow V5 it's compared against the 'engine_type' header -! field. In NetFlow V9 it's compared against the 3rd byte of -! the 'source_id' header field. Provides uniqueness with respect -! to the routing engine on the exporting device. -! 'engine_id' In NetFlow V5 it's compared against the 'engine_id' header -! field. In NetFlow V9 it's compared against the 4th byte of -! the 'source_id' header field. It provides uniqueness with -! respect to the particular line card or VIP on the exporting -! device. +! 'engine_type' In NetFlow V5 it's compared against the 'engine_type' +! header field. In NetFlow V9 it's compared against the +! 3rd octet of the 'source_id' header field. Provides +! uniqueness with respect to the routing engine on the +! exporting device. +! 'engine_id' In NetFlow V5 it's compared against the 'engine_id' +! header field. In NetFlow V9 it's compared against the +! 4th octet of the 'source_id' header field. It provides +! uniqueness with respect to the particular line card on +! the exporting device. ! 'nexthop' IPv4/IPv6 address of the next-hop router ! 'bgp_nexthop' IPv4/IPv6 address of the next-hop BGP router -! 'filter' Matches incoming packets against the supplied filter expression -! (expected in libpcap syntax); the filter needs to be enclosed in -! quotes ('). In order to get support for MPLS label hierarchies, -! the use of CVS versions >= 06-06-2005 of libpcap is adviceable: -! they include the support for expressions like "mpls 100000 and -! mpls 1024" that will match packets/flows with an outer label of -! 100000 and an inner label of 1024. -! 'v8agg' In NetFlow V8 it's compared against the aggregation method in use. -! Valid values are in the range 0 > value > 15. -! 'agent_id' In sFlow v5 it's compared against the subAgentId field. sFlow v2 -! and v4 lack of such field, so it does not apply. -! 'sampling_rate' In sFlow v2/v4/v5 it is compared against the sampling_rate field; -! It also works against NetFlow v5. NetFlow v9 is unsupported. -! 'direction' In NetFlow v9 it is compared against the direction (61) field, -! which only valid values are 0 (ingress) and 1 (egress) flow. -! 'src_as' source Autonomous System Number. In pmacctd it works only against -! a Networks map (see 'networks_file' directive); in nf|sfacctd it -! works against a Networks Map, the source ASN field in either sFlow -! or NetFlow datagrams and, since release 0.12.0, the BGP RIB of the -! exporting device (see 'nfacctd_bgp' directive). -! 'dst_as' destination Autonomous System Number. Same 'src_as' remarks hold -! here. Please read them above. -! 'peer_src_as' peering source Autonomous System Number. This is compared against -! the BGP RIB of the exporting device (see 'nfacctd_bgp' directive). -! 'peer_dst_as' peering destination Autonomous System Number. Same 'peer_src_as' +! 'filter' Matches incoming packets against the supplied filter +! expression (expected in libpcap syntax); the filter +! needs to be enclosed in quotes ('). +! 'v8agg' In NetFlow V8 this is compared against the aggregation +! method in use. Valid values are in the range 0 > value +! > 15. +! 'agent_id' In sFlow v5 it's compared against the subAgentId field. +! sFlow v2/v4 do not carry such field, hence it does not +! apply. +! 'sampling_rate' In sFlow v2/v4/v5 this is compared against the sampling +! rate field; it also works against NetFlow v5. NetFlow v9 +! is unsupported instead. +! 'direction' In NetFlow v9 it is compared against the direction (61) +! field, which only valid values are 0 (ingress) and 1 +! (egress) flow. +! 'src_as' source Autonomous System Number. Whether BGP daemon is +! not enabled in pmacctd it works only against a Networks +! map (see 'networks_file' directive); in nfacctd and +! sfacctd it works against a Networks Map, the source ASN +! field in either sFlow or NetFlow datagrams. Since 0.12, +! this can be compared against the corresponding BGP RIB +! of the exporting device (see 'bgp_daemon' configuration +! directive). +! 'dst_as' destination Autonomous System Number. Same 'src_as' ! remarks hold here. Please read them above. -! 'src_local_pref' Source IP prefix BGP local preference attribute. This is compared -! against the BGP RIB of the exporting device. -! 'local_pref' Destination IP prefix BGP local preference attribute. This is -! compared against the BGP RIB of the exporting device. -! 'src_comms' Source IP prefix BGP standard communities; multiple elements, up to -! 16, can be supplied, comma-separated (no spaces allowed); the check -! is successful if any of the communities is matched. This is compared -! against the BGP RIB of the exporting device. See examples below. -! 'comms' Destination IP prefix BGP standard communities; multiple elements, -! up to 16, can be supplied, comma-separated (no spaces allowed); the -! check is successful if any of the communities is matched. This is -! compared against the BGP RIB of the exporting device. See examples -! below. -! 'label' Mark the rule with label's value. Labels don't need to be unique: -! when jumping, the first matching label wins. Label value "next" -! is reserved for internal use and hence not to be used in a map. -! Using it might give unexpected results. -! 'jeq' Jump on EQual. Jumps to the supplied label in case of rule match. -! Jumps are Only forward. Label "next" is reserved and causes to go -! to the next rule, if any. -! Before continuing the map workflow, tagged data can be optionally -! returned to active plugins (ie. jeq=xxx return=true). Disabled by -! default (ie. return=false). Beware setting return=true, depending -! on configuration, can generate spurious data and/or duplicates; -! the logics by which this would work is: plugins which include 'tag' -! as aggregation will receive each tagged copy (if not filtered out -! by the pre_tag_filter directive, indeed); plugins not configured -! for tags will only receive a single copy of the data. -! 'return' Works only associated to a 'jeq' and is set to 'false' by default. -! Read full context details in the 'jeq' section. If set to 'true', -! after tagged data is sent for accounting the tag is reset making -! in practice this feature mutually exclusive with a 'stack' one. -! 'stack' Currently '+' (ie. sum symbol) is the unique supported value. This -! key makes sense only if JEQs are in use. When matching, accumulate -! tags, using the specified operator/function. By setting 'stack=+', -! the resulting tag would be: =. +! 'peer_src_as' peering source Autonomous System Number. It is compared +! against the corresponding BGP RIB of the exporting +! device (see 'bgp_daemon' configuration directive). +! 'peer_dst_as' peering destination Autonomous System Number. Same +! 'peer_src_as' remarks hold here. Please read them above. +! 'src_local_pref' Source IP prefix BGP local preference attribute. This is +! compared against the BGP RIB of the exporting device. +! 'local_pref' Destination IP prefix BGP local preference attribute. +! This is compared against the BGP RIB of the exporting +! device. +! 'src_comms' Source IP prefix BGP standard communities attribbute; +! multiple elements, up to 16, can be supplied, comma- +! separated (no spaces allowed); the check is successful +! if any of the communities is matched. This is compared +! against the BGP RIB of the exporting device. Examples +! are provided below. +! 'comms' Destination IP prefix BGP standard communities; multiple +! elements, up to 16, can be supplied, comma-separated (no +! spaces allowed); the check is successful if any of the +! communities is matched. This is compared against the BGP +! RIB of the exporting device. See examples below. +! 'label' Mark the rule with label's value. Labels don't need to +! be unique: when jumping, the first matching label wins. +! Label value 'next' is reserved for internal use and +! hence must not be used in a map. Doing otherwise might +! give unexpected results. +! 'jeq' Jump on EQual. Jumps to the supplied label in case of +! rule match. Jumps are Only forward. Label "next" is +! reserved and causes to go to the next rule, if any. +! Before continuing the map workflow, tagged data can be +! optionally returned to plugins (jeq=xxx return=true). +! Disabled by default (ie. return=false). Beware setting +! return=true, depending on configurations, can generate +! spurious data or duplicates; the logics with which this +! is intended to work is: plugins which include 'tag' in +! their aggregation method will receive each tagged copy +! (if not filtered out by the pre_tag_filter directive); +! plugins not configured for tags will only receive a +! single copy of the data. +! 'return' Works only associated to a 'jeq' and is set to 'false' +! by default. Read full details in the 'jeq' section. If +! set to 'true', after tagged data is sent for accounting, +! the tag is zeroed making essentially this feature not +! compatible with a 'stack' one. +! 'stack' Currently '+' (ie. sum symbol) is the unique supported +! value. This key makes sense only if JEQs are in use. +! When matching, accumulate tags, using the specified +! operator/function. By setting 'stack=+', the resulting +! tag would be: =. ! - ! -! A few examples NetFlow-related. The format of the rules is the same of 'sfacctd' ones -! but some keys don't apply to it. Note that the format of 'pmacctd' rules is slightly -! different. +! Examples: +! +! Some examples applicable to NetFlow. ! id=1 ip=192.168.2.1 in=4 id=10 ip=192.168.1.1 in=5 out=3 @@ -128,7 +152,7 @@ ! ! A few examples sFlow-related. The format of the rules is the same of 'nfacctd' ones -! but some keys don't apply to it. Note that the format of 'pmacctd' rules differs. +! but some keys don't apply to it. ! id=30 ip=192.168.1.1 id=31 ip=192.168.1.1 out=50 @@ -205,3 +229,26 @@ id=200 ip=192.168.1.1 comms=65000:3456 label=65000:3456 ! ! === +! +! === sfprobe/nfprobe: determining semi-dynamically direction and ifindex +! - Two steps approach: +! > determine direction first (1=in, 2=out) +! > then short circuit it to return an ifindex value +! - Configuration would look like the following fragment: +! ... +! nfprobe_direction: tag +! nfprobe_ifindex: tag2 +! ... +! +id=1 filter='ether dst 00:11:22:33:44:55' jeq=fivefive +id=1 filter='ether dst 00:11:22:33:44:66' jeq=sixsix +id=1 filter='ether dst 00:11:22:33:44:77' jeq=sevenseven +id=2 filter='ether src 00:11:22:33:44:55' jeq=fivefive +id=2 filter='ether src 00:11:22:33:44:66' jeq=sixsix +id=2 filter='ether src 00:11:22:33:44:77' jeq=sevenseven +! +id2=5 label=fivefive +id2=6 label=sixsix +id2=7 label=sevenseven +! +! === diff -Nru pmacct-0.12.1/EXAMPLES pmacct-0.12.5/EXAMPLES --- pmacct-0.12.1/EXAMPLES 2010-04-04 21:03:26.000000000 +0000 +++ pmacct-0.12.5/EXAMPLES 2010-10-26 17:06:40.000000000 +0000 @@ -13,6 +13,7 @@ IX. Quickstart guide to setup a NetFlow agent/probe X. Quickstart guide to setup a sFlow agent/probe XI. Quickstart guide to setup the BGP daemon +XII. Quickstart guide to setup a NetFlow/sFlow replicator I. Plugins included with pmacct distribution @@ -446,8 +447,6 @@ ! nfprobe_timeouts: tcp=120:maxlife=3600 ! ! networks_file: /path/to/networks.lst -! classifiers: /path/to/classifiers/ -! snaplen: 700 !... This is a basic working configuration. Additional features include: 1) generate ASNs @@ -477,11 +476,54 @@ neighbor 127.0.0.1 update-source X.X.X.X ! - 2) embed flow classification informations in NetFlow v9 datagrams by uncommenting - 'classifiers' and 'snaplen' lines, reading for further information the section of - this document about stream classification and finally adding the 'class' key to the - 'aggregate' directive; 3) add L2 (MAC addresses, VLANs) information to NetFlow v9 - flowsets. + 2) encode flow classification information in NetFlow v9 like Cisco does with its + NBAR/NetFlow v9 tie-up. This can be done by introducing the 'class' primitive to + the afore mentioned 'aggregate' and add the extra configuration directives: + +aggregate: class, src_host, dst_host, src_port, dst_port, proto, tos +classifiers: /path/to/classifiers/ +snaplen: 700 + + Further information on this topic can be found in the section of this document about + stream classification; 3) add direction (ingress, egress) awareness to measured IP + traffic flows. Direction can be inferred either statically (in, out) or dinamically + (tag, tag2) via nfprobe_direction directive. Let's look at a dynamic example using + tag2; first, add the following lines to the daemon configuration: + +nfprobe_direction: tag2 +pre_tag_map: /path/to/pretag.map + + then edit the tag map as follows. A return value of '1' means ingress while '2' is + translated to egress. It is possible to employ L2 and/or L3 addresses to recognize + flow directions. The 'id2' primitive (tag2) will be used to carry the return value: + +id=1 filter='dst host XXX.XXX.XXX.XXX' +id=2 filter='src host XXX.XXX.XXX.XXX' + +id=1 filter='ether src XX:XX:XX:XX:XX:XX' +id=2 filter='ether dst XX:XX:XX:XX:XX:XX' + + Indeed in such a case, the 'id' primitive (tag) can be leveraged to other uses (ie. + filter sub-set of the traffic for flow export); 4) add interface (input, output) + awareness to measured IP traffic flowsi - in addition to direction awareness, as + just discussed. Interface can be inferred either statically (<1-4294967295>) or + dynamically (tag, tag2) via nfprobe_ifindex directive. Let's look at a dynamic + example using tag; first add the following lines to the daemon configuration: + +nfprobe_direction: tag +pre_tag_map: /path/to/pretag.map + + then edit the tag map as follows. It is possible to employ L2 and/or L3 addresses + to recognize flow directions. The 'id' primitive (tag) will be used to carry the + return value: + +id=100 filter='dst host XXX.XXX.XXX.XXX' +id=100 filter='src host XXX.XXX.XXX.XXX' +id=200 filter='dst host YYY.YYY.YYY.YYY' +id=200 filter='src host YYY.YYY.YYY.YYY' + +id=200 filter='ether src YY:YY:YY:YY:YY:YY' +id=200 filter='ether dst YY:YY:YY:YY:YY:YY' c) build NetFlow collector configuration, using nfacctd: ! @@ -775,3 +817,46 @@ on the radar. For a review of all the configurable knobs and features see the CONFIG-KEYS document. + +XII. Quickstart guide to setup a NetFlow/sFlow replicator +pmacct 0.12 (>= 0.12.2) includes a new 'tee' plugin which is meant to replicate +NetFlow/sFlow data to N remote collectors. The plugin can also act transparently +by preserving the original IP address of the datagrams. +Setting up a replicator is very easy. All is needed is where to listen to for +incoming packets, where to replicate them to and optionally a filtering layer, +if required. Filtering bases on the standard pre_tag_map infrastructure; only +coarse-grained filtering against original source IP address is possible. + +nfacctd_port: 2100 +nfacctd_ip: X.X.X.X + +plugins: tee[a], tee[b] +tee_receiver[a]: Y.Y.Y.Y:2100 +tee_receiver[b]: Z.Z.Z.Z:2100 +! tee_transparent: true + +! pre_tag_map: /path/to/pretag.map +! pre_tag_filter[b]: 0 + +plugin_buffer_size: 10240 +plugin_pipe_size: 1024000 + +The pre_tag_filter in the above configuration snapshot applies only to the 'tee' +plugin instance 'b' and filters out any NetFlow/sFlow packets marked with a non- +zero 'id'. Plugin instance 'a' would normally receive all packets instead. An +example of the pre_tag_map content follows: + +id=1 ip=A.A.A.A +id=1 ip=B.B.B.B +id=1 ip=C.C.C.C + +To enable the transparent mode, the tee_transparent should be commented out. It +preserves the original IP address of the NetFlow/sFlow sender while replicating +by essentially spoofing it. This feature is not global and can be freely enabled +only on a subset of the active replicators. It requires super-user permissions +in order to run. + +Concluding note: 'tee' plugin is not compatible with different plugins - within +the same daemon instance. So if in the need of using pmacct for both collecting +and replicating data, two separate instances must be used (intuitively with the +replicator instance feeding the collector one). diff -Nru pmacct-0.12.1/FAQS pmacct-0.12.5/FAQS --- pmacct-0.12.1/FAQS 2009-10-25 11:22:47.000000000 +0000 +++ pmacct-0.12.5/FAQS 2010-05-14 15:06:58.000000000 +0000 @@ -1,5 +1,5 @@ pmacct (Promiscuous mode IP Accounting package) -pmacct is Copyright (C) 2003-2009 by Paolo Lucente +pmacct is Copyright (C) 2003-2010 by Paolo Lucente Q1: What is pmacct project homepage ? A: It is http://www.pmacct.net/ . There isn't any official mirror site. @@ -22,12 +22,12 @@ Q4: What are pmacct main features? -A: pmacct can collect and export network data. Collect in memory tables, SQL databases - (MySQL, PostgreSQL, SQLite 3.x). Export data speaking sFlow v5 and NetFlow v1/v5/v9. - pmacct is able to perform data aggregation; it can also filter, sample, renormalize, - tag, classify at L7. Since major release 0.12, pmacct integrates a skinny BGP daemon - within its NetFlow and sFlow collectors with the purpose of augment visibility into - the network traffic. +A: pmacct can collect, replicate and export network data. Collect in memory tables or + open-source SQL databases (MySQL, PostgreSQL, SQLite 3.x). Export speaking sFlow v5 + and NetFlow v1/v5/v9. pmacct is able to perform data aggregation; it can also filter, + sample, renormalize, tag, classify at L7. With release 0.12 pmacct integrates a BGP + BGP daemon within its NetFlow and sFlow collectors aimed at increasing visibility + into the network traffic. Q5: Does any of the pmacct daemons logs to flat files? @@ -283,6 +283,9 @@ * Don't rely automagically on standard indexes but enable optimal indexes based on clauses you (by means of reports, 3rd party tools, scripts, etc.) and pmacct use the most to SELECT data. Then remove every unused index. + * See if the dynamic table strategy offered by pmacct fits the bill: helps keeping + SQL tables and indexes of a manageable size by rotating SQL tables (ie. per hour, + day, week, etc.). See the 'sql_table_schema' configuration directive. * Run all SELECT and UPDATE queries under the "EXPLAIN ANALYZE ..." method to see if they are actually hitting the indexes. If not, you need to build indexes that better fit the actual scenario. diff -Nru pmacct-0.12.1/sql/pmacct-create-db_v8.mysql pmacct-0.12.5/sql/pmacct-create-db_v8.mysql --- pmacct-0.12.1/sql/pmacct-create-db_v8.mysql 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/sql/pmacct-create-db_v8.mysql 2010-10-06 07:26:12.000000000 +0000 @@ -0,0 +1,28 @@ +drop database if exists pmacct; +create database pmacct; + +use pmacct; + +drop table if exists acct_v8; +create table acct_v8 ( + agent_id INT(4) UNSIGNED NOT NULL, + class_id CHAR(16) NOT NULL, + mac_src CHAR(17) NOT NULL, + mac_dst CHAR(17) NOT NULL, + vlan INT(2) UNSIGNED NOT NULL, + as_src INT(4) UNSIGNED NOT NULL, + as_dst INT(4) UNSIGNED NOT NULL, + ip_src CHAR(15) NOT NULL, + ip_dst CHAR(15) NOT NULL, + port_src INT(2) UNSIGNED NOT NULL, + port_dst INT(2) UNSIGNED NOT NULL, + tcp_flags INT(4) UNSIGNED NOT NULL, + ip_proto CHAR(6) NOT NULL, + tos INT(4) UNSIGNED NOT NULL, + packets INT UNSIGNED NOT NULL, + bytes BIGINT UNSIGNED NOT NULL, + flows INT UNSIGNED NOT NULL, + stamp_inserted DATETIME NOT NULL, + stamp_updated DATETIME, + PRIMARY KEY (agent_id, class_id, mac_src, mac_dst, vlan, as_src, as_dst, ip_src, ip_dst, port_src, port_dst, ip_proto, tos, stamp_inserted) +); diff -Nru pmacct-0.12.1/sql/pmacct-create-table_v8.sqlite3 pmacct-0.12.5/sql/pmacct-create-table_v8.sqlite3 --- pmacct-0.12.1/sql/pmacct-create-table_v8.sqlite3 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/sql/pmacct-create-table_v8.sqlite3 2010-10-06 07:26:12.000000000 +0000 @@ -0,0 +1,23 @@ +DROP TABLE acct_v8; +CREATE TABLE acct_v8 ( + agent_id INT(8) NOT NULL DEFAULT 0, + class_id CHAR(16) NOT NULL DEFAULT ' ', + mac_src CHAR(17) NOT NULL DEFAULT '0:0:0:0:0:0', + mac_dst CHAR(17) NOT NULL DEFAULT '0:0:0:0:0:0', + vlan INT(4) NOT NULL DEFAULT 0, + as_src INT(8) NOT NULL DEFAULT 0, + as_dst INT(8) NOT NULL DEFAULT 0, + ip_src CHAR(15) NOT NULL DEFAULT '0.0.0.0', + ip_dst CHAR(15) NOT NULL DEFAULT '0.0.0.0', + port_src INT(4) NOT NULL DEFAULT 0, + port_dst INT(4) NOT NULL DEFAULT 0, + tcp_flags INT(4) NOT NULL DEFAULT 0, + ip_proto CHAR(6) NOT NULL DEFAULT 0, + tos INT(4) NOT NULL DEFAULT 0, + packets INT NOT NULL, + bytes BIGINT NOT NULL, + flows INT NOT NULL DEFAULT 0, + stamp_inserted DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', + stamp_updated DATETIME, + PRIMARY KEY (agent_id, class_id, mac_src, mac_dst, vlan, as_src, as_dst, ip_src, ip_dst, port_src, port_dst, ip_proto, tos, stamp_inserted) +); diff -Nru pmacct-0.12.1/sql/README.cos pmacct-0.12.5/sql/README.cos --- pmacct-0.12.1/sql/README.cos 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/sql/README.cos 2010-06-07 01:21:57.000000000 +0000 @@ -0,0 +1,13 @@ +This document doesn't replace documentation relevant to the database software you are +using, ie. README.mysql, README.pgsql or README.sqlite3. + +The 'cos' field. +Such field is being introduced to support 802.1p priority bits. The guidelines below +(typically in MySQL format) are to add such primitives to the SQL schema: + +* cos field: + - "cos INT(1) UNSIGNED NOT NULL," to declare the field itself + - "PRIMARY KEY (..., cos, ...)" to put it in the primary key + +The primitive is not declared as part of any default table version; yet will not fail +version checks which are enabled when 'sql_optimize_clauses' feature is disabled. diff -Nru pmacct-0.12.1/sql/README.mysql pmacct-0.12.5/sql/README.mysql --- pmacct-0.12.1/sql/README.mysql 2010-03-05 17:44:49.000000000 +0000 +++ pmacct-0.12.5/sql/README.mysql 2010-10-06 07:26:12.000000000 +0000 @@ -54,28 +54,64 @@ - To understand difference between the various BGP table versions: * Only BGP table v1 is currently available. -- Primitives not included in any default SQL table schema: +- Aggregation primitives to SQL schema mapping: Aggregation primitive => SQL table field - * src_std_comm => comms_src (declared same as 'comms') - * src_ext_comm => comms_src (declared same as 'comms') - * src_as_path => as_path_src (declared same as 'as_path') - * src_local_pref => local_pref_src (declared same as 'local_pref') - * src_med => med_src (declared same as 'med') - * is_symmetric => is_symmetric (see README.is_symmetric) - * tag2 => agent_id2 (see README.agent_id2) - * in_iface => iface_in (see README.iface) - * out_iface => iface_out (see README.iface) - * src_mask => mask_src (see README.mask) - * dst_mask => mask_dst (see README.mask) + * tag => agent_id (INT(4) UNSIGNED NOT NULL) + * tag2 => agent_id2 (INT(4) UNSIGNED NOT NULL, see README.agent_id2) + * src_as => as_src (INT(4) UNSIGNED NOT NULL) + * dst_as => as_dst (INT(4) UNSIGNED NOT NULL) + * peer_src_as => peer_as_src (INT(4) UNSIGNED NOT NULL) + * peer_dst_as => peer_as_dst (INT(4) UNSIGNED NOT NULL) + * peer_src_ip => peer_ip_src (CHAR(15) NOT NULL, see README.IPv6) + * peer_dst_ip => peer_ip_dst (CHAR(15) NOT NULL, see README.IPv6) + * std_comm => comms (CHAR(24) NOT NULL) + * ext_comm => comms (CHAR(24) NOT NULL) + * as_path => as_path (CHAR(21) NOT NULL) + * local_pref => local_pref (INT(4) UNSIGNED NOT NULL) + * med => med (INT(4) UNSIGNED NOT NULL) + * src_std_comm => comms_src (CHAR(24) NOT NULL) + * src_ext_comm => comms_src (CHAR(24) NOT NULL) + * src_as_path => as_path_src (CHAR(21) NOT NULL) + * src_local_pref => local_pref_src (INT(4) UNSIGNED NOT NULL) + * src_med => med_src (INT(4) UNSIGNED NOT NULL) + * is_symmetric => is_symmetric (INT(1) UNSIGNED NOT NULL, see README.is_symmetric) + * in_iface => iface_in (INT(4) UNSIGNED NOT NULL, see README.iface) + * out_iface => iface_out (INT(4) UNSIGNED NOT NULL, see README.iface) + * src_mask => mask_src (INT(1) UNSIGNED NOT NULL, see README.mask) + * dst_mask => mask_dst (INT(1) UNSIGNED NOT NULL, see README.mask) + * cos => cos (INT(1) UNSIGNED NOT NULL, see README.cos) + * class => class_id (CHAR(16) NOT NULL) + * src_mac => mac_src (CHAR(17) NOT NULL) + * dst_mac => mac_dst (CHAR(17) NOT NULL) + * vlan => vlan (INT(2) UNSIGNED NOT NULL) + * src_as => as_src (INT(4) UNSIGNED NOT NULL) + * dst_as => as_dst (INT(4) UNSIGNED NOT NULL) + * src_host => ip_src (CHAR(15) NOT NULL, see README.IPv6) + * dst_host => ip_dst (CHAR(15) NOT NULL, see README.IPv6) + * src_net => ip_src (CHAR(15) NOT NULL, see README.IPv6) + * dst_net => ip_dst (CHAR(15) NOT NULL, see README.IPv6) + * src_port => src_port (INT(2) UNSIGNED NOT NULL) + - src_port => port_src (INT(2) UNSIGNED NOT NULL, if sql_table_version: 8) + * dst_port => dst_port (INT(2) UNSIGNED NOT NULL) + - dst_port => port_dst (INT(2) UNSIGNED NOT NULL, if sql_table_version: 8) + * tcpflags => tcp_flags (INT(4) UNSIGNED NOT NULL) + * proto => ip_proto (CHAR(6) NOT NULL) + * tos => tos (INT(4) UNSIGNED NOT NULL) + +- Counters and time reference need always to be defined as part of the SQL schema: + * packets (INT UNSIGNED NOT NULL) + * bytes (BIGINT UNSIGNED NOT NULL) + * stamp_inserted (DATETIME NOT NULL, enabled by sql_history) + * stamp_updated (DATETIME, enabled by sql_history) NOTE: mind to specify EVERYTIME which SQL table version you intend to adhere to by using either of the following rules: When using commandline options: - * -v [ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] + * -v [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] When using configuration directives: - * sql_table_version: [ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] + * sql_table_version: [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] * sql_table_type: [ bgp ] NOTE: specifying a non-documented SQL table profile will result diff -Nru pmacct-0.12.1/sql/README.pgsql pmacct-0.12.5/sql/README.pgsql --- pmacct-0.12.1/sql/README.pgsql 2010-03-05 17:44:49.000000000 +0000 +++ pmacct-0.12.5/sql/README.pgsql 2010-10-06 07:26:12.000000000 +0000 @@ -64,19 +64,53 @@ - To understand difference between the various BGP table versions: * Only BGP table v1 is currently available. -- Primitives not included in any default SQL table schema: +- Aggregation primitives to SQL schema mapping: Aggregation primitive => SQL table field - * src_std_comm => comms_src (declared same as 'comms') - * src_ext_comm => comms_src (declared same as 'comms') - * src_as_path => as_path_src (declared same as 'as_path') - * src_local_pref => local_pref_src (declared same as 'local_pref') - * src_med => med_src (declared same as 'med') - * is_symmetric => is_symmetric (see README.is_symmetric) - * tag2 => agent_id2 (see README.agent_id2) - * in_iface => iface_in (see README.iface) - * out_iface => iface_out (see README.iface) - * src_mask => mask_src (see README.mask) - * dst_mask => mask_dst (see README.mask) + * tag => agent_id (BIGINT NOT NULL DEFAULT 0) + * tag2 => agent_id2 (BIGINT NOT NULL DEFAULT 0, see README.agent_id2) + * src_as => as_src (BIGINT NOT NULL DEFAULT 0) + * dst_as => as_dst (BIGINT NOT NULL DEFAULT 0) + * peer_src_as => peer_as_src (BIGINT NOT NULL DEFAULT 0) + * peer_dst_as => peer_as_dst (BIGINT NOT NULL DEFAULT 0) + * peer_src_ip => peer_ip_src (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * peer_dst_ip => peer_ip_dst (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * std_comm => comms (CHAR(24) NOT NULL DEFAULT ' ') + * ext_comm => comms (CHAR(24) NOT NULL DEFAULT ' ') + * as_path => as_path (CHAR(21) NOT NULL DEFAULT ' ') + * local_pref => local_pref (BIGINT NOT NULL DEFAULT 0) + * med => med (BIGINT NOT NULL DEFAULT 0) + * src_std_comm => comms_src (CHAR(24) NOT NULL DEFAULT ' ') + * src_ext_comm => comms_src (CHAR(24) NOT NULL DEFAULT ' ') + * src_as_path => as_path_src (CHAR(21) NOT NULL DEFAULT ' ') + * src_local_pref => local_pref_src (BIGINT NOT NULL DEFAULT 0) + * src_med => med_src (BIGINT NOT NULL DEFAULT 0) + * is_symmetric => is_symmetric (SMALLINT NOT NULL DEFAULT 0, see README.is_symmetric) + * in_iface => iface_in (BIGINT NOT NULL DEFAULT 0, see README.iface) + * out_iface => iface_out (BIGINT NOT NULL DEFAULT 0, see README.iface) + * src_mask => mask_src (SMALLINT NOT NULL DEFAULT 0, see README.mask) + * dst_mask => mask_dst (SMALLINT NOT NULL DEFAULT 0, see README.mask) + * cos => cos (SMALLINT NOT NULL DEFAULT 0, see README.cos) + * class => class_id (CHAR(16) NOT NOT NULL DEFAULT ' ') + * src_mac => mac_src (macaddr NOT NULL DEFAULT '0:0:0:0:0:0') + * dst_mac => mac_dst (macaddr NOT NULL DEFAULT '0:0:0:0:0:0') + * vlan => vlan (INT NOT NULL DEFAULT 0) + * src_as => as_src (BIGINT NOT NULL DEFAULT 0) + * dst_as => as_dst (BIGINT NOT NULL DEFAULT 0) + * src_host => ip_src (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * dst_host => ip_dst (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * src_net => ip_src (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * dst_net => ip_dst (inet NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * src_port => port_src (INT NOT NULL DEFAULT 0) + * dst_port => port_dst (INT NOT NULL DEFAULT 0) + * tcpflags => tcp_flags (SMALLINT NOT NULL DEFAULT 0) + * proto => ip_proto (SMALLINT NOT NULL DEFAULT 0) + * tos => tos (INT NOT NULL DEFAULT 0) + +- Counters and time reference need always to be defined as part of the SQL schema: + * packets (INT UNSIGNED NOT NULL) + * bytes (BIGINT UNSIGNED NOT NULL) + * stamp_inserted (timestamp without time zone NOT NULL DEFAULT '0000-01-01 00:00:00', enabled by sql_history) + * stamp_updated (timestamp without time zone, enabled by sql_history) - What is the difference between 'typed' and 'unified' modes ? It applies to IP tables only (ie. not to BGP ones). The 'unified' table has IP addresses diff -Nru pmacct-0.12.1/sql/README.sqlite3 pmacct-0.12.5/sql/README.sqlite3 --- pmacct-0.12.1/sql/README.sqlite3 2010-03-05 17:44:49.000000000 +0000 +++ pmacct-0.12.5/sql/README.sqlite3 2010-10-06 07:26:12.000000000 +0000 @@ -55,28 +55,64 @@ - To understand difference between the various BGP table versions: * Only BGP table v1 is currently available. -- Primitives not included in any default SQL table schema: +- Aggregation primitives to SQL schema mapping: Aggregation primitive => SQL table field - * src_std_comm => comms_src (declared same as 'comms') - * src_ext_comm => comms_src (declared same as 'comms') - * src_as_path => as_path_src (declared same as 'as_path') - * src_local_pref => local_pref_src (declared same as 'local_pref') - * src_med => med_src (declared same as 'med') - * is_symmetric => is_symmetric (see README.is_symmetric) - * tag2 => agent_id2 (see README.agent_id2) - * in_iface => iface_in (see README.iface) - * out_iface => iface_out (see README.iface) - * src_mask => mask_src (see README.mask) - * dst_mask => mask_dst (see README.mask) + * tag => agent_id (INT(8) NOT NULL DEFAULT 0) + * tag2 => agent_id2 (INT(8) NOT NULL DEFAULT 0, see README.agent_id2) + * src_as => as_src (INT(8) NOT NULL DEFAULT 0) + * dst_as => as_dst (INT(8) NOT NULL DEFAULT 0) + * peer_src_as => peer_as_src (INT(8) NOT NULL DEFAULT 0) + * peer_dst_as => peer_as_dst (INT(8) NOT NULL DEFAULT 0) + * peer_src_ip => peer_ip_src (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * peer_dst_ip => peer_ip_dst (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * std_comm => comms (CHAR(24) NOT NULL DEFAULT ' ') + * ext_comm => comms (CHAR(24) NOT NULL DEFAULT ' ') + * as_path => as_path (CHAR(21) NOT NULL DEFAULT ' ') + * local_pref => local_pref (INT(8) NOT NULL DEFAULT 0) + * med => med (INT(8) NOT NULL DEFAULT 0) + * src_std_comm => comms_src (CHAR(24) NOT NULL DEFAULT ' ') + * src_ext_comm => comms_src (CHAR(24) NOT NULL DEFAULT ' ') + * src_as_path => as_path_src (CHAR(21) NOT NULL DEFAULT ' ') + * src_local_pref => local_pref_src (INT(8) NOT NULL DEFAULT 0) + * src_med => med_src (INT(8) NOT NULL DEFAULT 0) + * is_symmetric => is_symmetric (INT(2) NOT NULL DEFAULT 0, see README.is_symmetric) + * in_iface => iface_in (INT(8) NOT NULL DEFAULT 0, see README.iface) + * out_iface => iface_out (INT(8) NOT NULL DEFAULT 0, see README.iface) + * src_mask => mask_src (INT(2) NOT NULL DEFAULT 0, see README.mask) + * dst_mask => mask_dst (INT(2) NOT NULL DEFAULT 0, see README.mask) + * cos => cos (INT(2) NOT NULL DEFAULT 0, see README.cos) + * class => class_id (CHAR(16) NOT NOT NULL DEFAULT ' ') + * src_mac => mac_src (CHAR(17) NOT NULL DEFAULT '0:0:0:0:0:0') + * dst_mac => mac_dst (CHAR(17) NOT NULL DEFAULT '0:0:0:0:0:0') + * vlan => vlan (INT(4) NOT NULL DEFAULT 0) + * src_as => as_src (INT(8) NOT NULL DEFAULT 0) + * dst_as => as_dst (INT(8) NOT NULL DEFAULT 0) + * src_host => ip_src (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * dst_host => ip_dst (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * src_net => ip_src (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * dst_net => ip_dst (CHAR(15) NOT NULL DEFAULT '0.0.0.0', see README.IPv6) + * src_port => src_port (INT(4) NOT NULL DEFAULT 0) + - src_port => port_src (INT(4) NOT NULL DEFAULT 0, if sql_table_version: 8) + * dst_port => dst_port (INT(4) NOT NULL DEFAULT 0) + - dst_port => port_dst (INT(4) NOT NULL DEFAULT 0, if sql_table_version: 8) + * tcpflags => tcp_flags (INT(2) NOT NULL DEFAULT 0) + * proto => ip_proto (INT(2) NOT NULL DEFAULT 0) + * tos => tos (INT(4) NOT NULL DEFAULT 0) + +- Counters and time reference need always to be defined as part of the SQL schema: + * packets (INT(4) UNSIGNED NOT NULL) + * bytes (INT(8) UNSIGNED NOT NULL) + * stamp_inserted (DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', enabled by sql_history) + * stamp_updated (DATETIME, enabled by sql_history) NOTE: mind to specify EVERYTIME which SQL table version you intend to adhere to by using either of the following rules: When using commandline options: - * -v [ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] + * -v [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] When using configuration directives: - * sql_table_version: [ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] + * sql_table_version: [ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] * sql_table_type: [ bgp ] NOTE: specifying a non-documented SQL table profile will result diff -Nru pmacct-0.12.1/src/addr.c pmacct-0.12.5/src/addr.c --- pmacct-0.12.1/src/addr.c 2009-07-29 17:04:48.000000000 +0000 +++ pmacct-0.12.5/src/addr.c 2010-06-07 01:21:57.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -326,11 +326,9 @@ { #if defined IM_LITTLE_ENDIAN static u_int64_t buf; - register u_int32_t *x = (u_int32_t *)(void *) &addr; - register u_int32_t *y = (u_int32_t *)(void *) &buf; - y[0] = ntohl(x[1]); - y[1] = ntohl(x[0]); + buf = ((u_int64_t) ntohl(addr & 0xFFFFFFFFLLU)) << 32; + buf |= ntohl((addr & 0xFFFFFFFF00000000LLU) >> 32); return buf; #else diff -Nru pmacct-0.12.1/src/bgp/bgp.c pmacct-0.12.5/src/bgp/bgp.c --- pmacct-0.12.1/src/bgp/bgp.c 2010-03-16 21:58:28.000000000 +0000 +++ pmacct-0.12.5/src/bgp/bgp.c 2010-12-21 16:56:52.000000000 +0000 @@ -70,12 +70,14 @@ u_int32_t remote_as4 = 0; time_t now; struct hosts_table allow; + struct bgp_md5_table bgp_md5; /* select() stuff */ fd_set read_descs, bkp_read_descs; int select_fd, select_num; /* initial cleanups */ + reload_map_bgp_thread = FALSE; memset(&server, 0, sizeof(server)); memset(&client, 0, sizeof(client)); memset(bgp_packet, 0, BGP_MAX_PACKET_SIZE); @@ -83,6 +85,15 @@ bgp_attr_init(); /* socket creation for BGP server: IPv4 only */ +#if (defined ENABLE_IPV6 && defined V4_MAPPED) + if (!config.nfacctd_bgp_ip) { + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)&server; + + sa6->sin6_family = AF_INET6; + sa6->sin6_port = htons(config.nfacctd_bgp_port); + slen = sizeof(struct sockaddr_in6); + } +#else if (!config.nfacctd_bgp_ip) { struct sockaddr_in *sa4 = (struct sockaddr_in *)&server; @@ -91,11 +102,12 @@ sa4->sin_port = htons(config.nfacctd_bgp_port); slen = sizeof(struct sockaddr_in); } +#endif else { trim_spaces(config.nfacctd_bgp_ip); ret = str_to_addr(config.nfacctd_bgp_ip, &addr); - if (!ret || addr.family != AF_INET) { - Log(LOG_ERR, "ERROR ( default/core/BGP ): 'nfacctd_bgp_ip' value is not a valid IPv4 address. Terminating thread.\n"); + if (!ret) { + Log(LOG_ERR, "ERROR ( default/core/BGP ): 'nfacctd_bgp_ip' value is not a valid IPv4/IPv6 address. Terminating thread.\n"); exit_all(1); } slen = addr_to_sa((struct sockaddr *)&server, &addr, config.nfacctd_bgp_port); @@ -107,11 +119,19 @@ peers = malloc(config.nfacctd_bgp_max_peers*sizeof(struct bgp_peer)); memset(peers, 0, config.nfacctd_bgp_max_peers*sizeof(struct bgp_peer)); + if (!config.bgp_table_peer_buckets) config.bgp_table_peer_buckets = DEFAULT_BGP_INFO_HASH; + sock = socket(((struct sockaddr *)&server)->sa_family, SOCK_STREAM, 0); if (sock < 0) { Log(LOG_ERR, "ERROR ( default/core/BGP ): thread socket() failed. Terminating thread.\n"); exit_all(1); } + if (config.nfacctd_bgp_ipprec) { + int opt = config.nfacctd_bgp_ipprec << 5; + + rc = setsockopt(sock, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); + if (rc < 0) Log(LOG_ERR, "WARN ( default/core/BGP ): setsockopt() failed for IP_TOS (errno: %d).\n", errno); + } rc = Setsocksize(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); if (rc < 0) Log(LOG_ERR, "WARN ( default/core/BGP ): Setsocksize() failed for SO_REUSEADDR (errno: %d).\n", errno); @@ -150,6 +170,19 @@ /* Preparing ACL, if any */ if (config.nfacctd_bgp_allow_file) load_allow_file(config.nfacctd_bgp_allow_file, &allow); + /* Preparing MD5 keys, if any */ + if (config.nfacctd_bgp_md5_file) { + load_bgp_md5_file(config.nfacctd_bgp_md5_file, &bgp_md5); + if (bgp_md5.num) process_bgp_md5_file(sock, &bgp_md5); + } + + /* Let's initialize clean shared RIB */ + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { + rib[afi][safi] = bgp_table_init(afi, safi); + } + } + for (;;) { select_again: select_fd = sock; @@ -160,6 +193,16 @@ select_num = select(select_fd, &read_descs, NULL, NULL, NULL); if (select_num < 0) goto select_again; + if (reload_map_bgp_thread) { + if (config.nfacctd_bgp_md5_file) { + unload_bgp_md5_file(&bgp_md5); + if (bgp_md5.num) process_bgp_md5_file(sock, &bgp_md5); // process unload + load_bgp_md5_file(config.nfacctd_bgp_md5_file, &bgp_md5); + if (bgp_md5.num) process_bgp_md5_file(sock, &bgp_md5); // process load + } + reload_map_bgp_thread = FALSE; + } + /* New connection is coming in */ if (FD_ISSET(sock, &read_descs)) { int peers_check_idx, peers_num; @@ -170,6 +213,7 @@ bgp_peer_init(peer); break; } + /* XXX: replenish sessions with expired keepalives */ } if (!peer) { @@ -193,12 +237,15 @@ } FD_SET(peer->fd, &bkp_read_descs); - peer->addr.family = AF_INET; - peer->addr.address.ipv4.s_addr = ((struct sockaddr_in *)&client)->sin_addr.s_addr; + peer->addr.family = ((struct sockaddr *)&client)->sa_family; + if (peer->addr.family == AF_INET) peer->addr.address.ipv4.s_addr = ((struct sockaddr_in *)&client)->sin_addr.s_addr; +#if defined ENABLE_IPV6 + else if (peer->addr.family == AF_INET6) memcpy(&peer->addr.address.ipv6, &((struct sockaddr_in6 *)&client)->sin6_addr, 16); +#endif /* Check: only one TCP connection is allowed per peer */ for (peers_check_idx = 0, peers_num = 0; peers_check_idx < config.nfacctd_bgp_max_peers; peers_check_idx++) { - if (peers_idx != peers_check_idx && peers[peers_check_idx].addr.address.ipv4.s_addr == peer->addr.address.ipv4.s_addr) { + if (peers_idx != peers_check_idx && !memcmp(&peers[peers_check_idx].addr, &peer->addr, sizeof(peers[peers_check_idx].addr))) { now = time(NULL); if ((now - peers[peers_check_idx].last_keepalive) > peers[peers_check_idx].ht) { Log(LOG_INFO, "INFO ( default/core/BGP ): [Id: %s] Replenishing stale connection by peer.\n", inet_ntoa(peers[peers_check_idx].id.address.ipv4)); @@ -207,6 +254,7 @@ } else { Log(LOG_ERR, "ERROR ( default/core/BGP ): [Id: %s] Refusing new connection from existing peer (residual holdtime: %u).\n", inet_ntoa(peers[peers_check_idx].id.address.ipv4), (peers[peers_check_idx].ht - (now - peers[peers_check_idx].last_keepalive))); + FD_CLR(peer->fd, &bkp_read_descs); bgp_peer_close(peer); goto select_again; } @@ -564,8 +612,16 @@ bopen_reply->bgpo_optlen = cp_msglen; bopen_reply->bgpo_len = htons(BGP_MIN_OPEN_MSG_SIZE + bopen_reply->bgpo_optlen); - if (config.nfacctd_bgp_ip) my_id = config.nfacctd_bgp_ip; - str_to_addr(my_id, &my_id_addr); + if (config.nfacctd_bgp_ip) { + my_id = config.nfacctd_bgp_ip; + str_to_addr(my_id, &my_id_addr); + if (my_id_addr.family != AF_INET) { + my_id = my_id_static; + str_to_addr(my_id, &my_id_addr); + } + } + else str_to_addr(my_id, &my_id_addr); + bopen_reply->bgpo_id = my_id_addr.address.ipv4.s_addr; memcpy(msg+BGP_MIN_OPEN_MSG_SIZE, cp_msg, cp_msglen); @@ -640,7 +696,7 @@ update.nlri = pkt; update.length = update_len; } - + if (withdraw.length) bgp_nlri_parse(peer, NULL, &withdraw); /* NLRI parsing */ @@ -649,22 +705,22 @@ if (mp_update.length && mp_update.afi == AFI_IP - && mp_update.safi == SAFI_UNICAST) + && (mp_update.safi == SAFI_UNICAST || mp_update.safi == SAFI_MPLS_LABEL)) bgp_nlri_parse(peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP - && mp_withdraw.safi == SAFI_UNICAST) + && (mp_withdraw.safi == SAFI_UNICAST || mp_withdraw.safi == SAFI_MPLS_LABEL)) bgp_nlri_parse (peer, NULL, &mp_withdraw); if (mp_update.length && mp_update.afi == AFI_IP6 - && mp_update.safi == SAFI_UNICAST) + && (mp_update.safi == SAFI_UNICAST || mp_update.safi == SAFI_MPLS_LABEL)) bgp_nlri_parse(peer, &attr, &mp_update); if (mp_withdraw.length && mp_withdraw.afi == AFI_IP6 - && mp_withdraw.safi == SAFI_UNICAST) + && (mp_withdraw.safi == SAFI_UNICAST || mp_withdraw.safi == SAFI_MPLS_LABEL)) bgp_nlri_parse (peer, NULL, &mp_withdraw); /* Receipt of End-of-RIB can be processed here; being a silent @@ -871,6 +927,7 @@ break; #if defined ENABLE_IPV6 case 16: + case 32: attr->mp_nexthop.family = AF_INET6; memcpy(&attr->mp_nexthop.address.ipv6, ptr, 16); break; @@ -936,6 +993,7 @@ { u_char *pnt; u_char *lim; + u_char safi; struct prefix p; int psize, end; int ret; @@ -945,6 +1003,7 @@ pnt = info->nlri; lim = pnt + info->length; end = info->length; + safi = info->safi; for (; pnt < lim; pnt += psize) { @@ -953,22 +1012,37 @@ /* Fetch prefix length and cross-check */ p.prefixlen = *pnt++; end--; p.family = bgp_afi2family (info->afi); - - if ((info->afi == AFI_IP && p.prefixlen > 32) || (info->afi == AFI_IP6 && p.prefixlen > 128)) return -1; - psize = ((p.prefixlen+7)/8); - if (psize > end) return -1; + if (info->safi == SAFI_UNICAST) { + if ((info->afi == AFI_IP && p.prefixlen > 32) || (info->afi == AFI_IP6 && p.prefixlen > 128)) return -1; + + psize = ((p.prefixlen+7)/8); + if (psize > end) return -1; + + /* Fetch prefix from NLRI packet. */ + memcpy(&p.u.prefix, pnt, psize); + + // XXX: check address correctnesss now that we have it? + } + else if (info->safi == SAFI_MPLS_LABEL) { /* rfc3107 labeled unicast */ + if ((info->afi == AFI_IP && p.prefixlen > 56) || (info->afi == AFI_IP6 && p.prefixlen > 152)) return -1; + + psize = ((p.prefixlen+7)/8); + if (psize > end) return -1; - /* Fetch prefix from NLRI packet. */ - memcpy(&p.u.prefix, pnt, psize); + /* Fetch prefix from NLRI packet, drop the 3 bytes label. */ + memcpy(&p.u.prefix, pnt+3, (psize-3)); + p.prefixlen -= 24; - // XXX: check address correctnesss now that we have it? + /* As we trash the label anyway, let's rewrite the SAFI as plain unicast */ + safi = SAFI_UNICAST; + } /* Let's do our job now! */ if (attr) - ret = bgp_process_update(peer, &p, attr, info->afi, info->safi); + ret = bgp_process_update(peer, &p, attr, info->afi, safi); else - ret = bgp_process_withdraw(peer, &p, attr, info->afi, info->safi); + ret = bgp_process_withdraw(peer, &p, attr, info->afi, safi); } return 0; @@ -979,19 +1053,18 @@ struct bgp_node *route; struct bgp_info *ri, *new; struct bgp_attr *attr_new; + u_int32_t modulo = peer->fd % config.bgp_table_peer_buckets; - route = bgp_node_get(peer->rib[afi][safi], p); + route = bgp_node_get(rib[afi][safi], p); /* Check previously received route. */ - for (ri = route->info; ri; ri = ri->next) - if (ri->peer == peer && ri->type == afi && ri->sub_type == safi) - break; + for (ri = route->info[modulo]; ri; ri = ri->next) { + if (ri->peer == peer) break; + } attr_new = bgp_attr_intern(attr); if (ri) { - ri->uptime = time(NULL); - /* Received same information */ if (attrhash_cmp(ri->attr, attr_new)) { bgp_unlock_node (route); @@ -1014,14 +1087,11 @@ /* Make new BGP info. */ new = bgp_info_new(); - new->type = afi; - new->sub_type = safi; new->peer = peer; new->attr = attr_new; - new->uptime = time(NULL); /* Register new BGP information. */ - bgp_info_add(route, new); + bgp_info_add(route, new, modulo); /* route_node_get lock */ bgp_unlock_node(route); @@ -1072,14 +1142,15 @@ { struct bgp_node *route; struct bgp_info *ri; + u_int32_t modulo = peer->fd % config.bgp_table_peer_buckets; /* Lookup node. */ - route = bgp_node_get(peer->rib[afi][safi], p); + route = bgp_node_get(rib[afi][safi], p); /* Lookup withdrawn route. */ - for (ri = route->info; ri; ri = ri->next) - if (ri->peer == peer && ri->type == afi && ri->sub_type == safi) - break; + for (ri = route->info[modulo]; ri; ri = ri->next) { + if (ri->peer == peer) break; + } if (ri && config.nfacctd_bgp_msglog) { char empty[] = ""; @@ -1093,11 +1164,12 @@ comm = ri->attr->community ? ri->attr->community->str : empty; ecomm = ri->attr->ecommunity ? ri->attr->ecommunity->str : empty; - Log(LOG_INFO, "INFO ( default/core/BGP ): [Id: %s] w Prefix: %s Path: '%s' Comms: '%s' EComms: '%s'\n", inet_ntoa(peer->id.address.ipv4), prefix_str, aspath, comm, ecomm); + Log(LOG_INFO, "INFO ( default/core/BGP ): [Id: %s] w Prefix: %s Path: '%s' Comms: '%s' EComms: '%s'\n", + inet_ntoa(peer->id.address.ipv4), prefix_str, aspath, comm, ecomm); } /* Withdraw specified route from routing table. */ - if (ri) bgp_info_delete(route, ri); + if (ri) bgp_info_delete(route, ri, modulo); /* Unlock bgp_node_get() lock. */ bgp_unlock_node(route); @@ -1128,36 +1200,33 @@ return new; } -void bgp_info_add(struct bgp_node *rn, struct bgp_info *ri) +void bgp_info_add(struct bgp_node *rn, struct bgp_info *ri, u_int32_t modulo) { struct bgp_info *top; - top = rn->info; + top = rn->info[modulo]; - ri->next = rn->info; + ri->next = rn->info[modulo]; ri->prev = NULL; if (top) top->prev = ri; - rn->info = ri; + rn->info[modulo] = ri; - ri->lock++; + // ri->lock++; bgp_lock_node(rn); ri->peer->lock++; } -void bgp_info_delete(struct bgp_node *rn, struct bgp_info *ri) +void bgp_info_delete(struct bgp_node *rn, struct bgp_info *ri, u_int32_t modulo) { if (ri->next) ri->next->prev = ri->prev; if (ri->prev) ri->prev->next = ri->next; else - rn->info = ri->next; - - assert (ri->lock > 0); + rn->info[modulo] = ri->next; - ri->lock--; - if (ri->lock == 0) bgp_info_free(ri); + bgp_info_free(ri); bgp_unlock_node(rn); } @@ -1338,13 +1407,6 @@ peer->buf.len = BGP_MAX_PACKET_SIZE; peer->buf.base = malloc(peer->buf.len); memset(peer->buf.base, 0, peer->buf.len); - - /* Let's initialize clean RIBs once again */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - peer->rib[afi][safi] = bgp_table_init(afi, safi); - } - } } void bgp_peer_close(struct bgp_peer *peer) @@ -1357,13 +1419,6 @@ memset(&peer->id, 0, sizeof(peer->id)); memset(&peer->addr, 0, sizeof(peer->addr)); - /* Let's fully invalidate current RIBs first */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) { - bgp_table_finish(&peer->rib[afi][safi]); - } - } - free(peer->buf.base); if (config.nfacctd_bgp_neighbors_file) @@ -1553,7 +1608,8 @@ void bgp_srcdst_lookup(struct packet_ptrs *pptrs) { struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local; - struct bgp_peer *peer, *saved_peer = NULL; + struct xflow_status_entry *xs_entry = (struct xflow_status_entry *) pptrs->f_status; + struct bgp_peer *peer; struct bgp_node *default_node, *result; struct bgp_info *info; struct prefix default_prefix; @@ -1563,11 +1619,14 @@ #if defined ENABLE_IPV6 struct in6_addr pref6; #endif + u_int32_t modulo; pptrs->bgp_src = NULL; pptrs->bgp_dst = NULL; + pptrs->bgp_src_info = NULL; + pptrs->bgp_dst_info = NULL; pptrs->bgp_peer = NULL; - pptrs->bgp_nexthop = NULL; + pptrs->bgp_nexthop_info = NULL; if (pptrs->bta) { sa = &sa_local; @@ -1578,27 +1637,87 @@ start_again: - for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) { - if (!sa_addr_cmp(sa, &peers[peers_idx].addr)) { - peer = &peers[peers_idx]; - pptrs->bgp_peer = (char *) &peers[peers_idx]; - break; + if (xs_entry && xs_entry->peer_idx) { + if (!sa_addr_cmp(sa, &peers[xs_entry->peer_idx].addr) || !sa_addr_cmp(sa, &peers[xs_entry->peer_idx].id)) { + peer = &peers[xs_entry->peer_idx]; + pptrs->bgp_peer = (char *) &peers[xs_entry->peer_idx]; + } + /* If no match then let's invalidate the entry */ + else { + xs_entry->peer_idx = 0; + peer = NULL; + } + } + else { + for (peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) { + if (!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) { + peer = &peers[peers_idx]; + pptrs->bgp_peer = (char *) &peers[peers_idx]; + if (xs_entry) xs_entry->peer_idx = peers_idx; + break; + } } } if (peer) { + modulo = peer->fd % config.bgp_table_peer_buckets; + if (pptrs->l3_proto == ETHERTYPE_IP) { - memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr)); - if (!pptrs->bgp_src) pptrs->bgp_src = (char *) bgp_node_match_ipv4(peer->rib[AFI_IP][SAFI_UNICAST], &pref4); - memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); - if (!pptrs->bgp_dst) pptrs->bgp_dst = (char *) bgp_node_match_ipv4(peer->rib[AFI_IP][SAFI_UNICAST], &pref4); + if (!pptrs->bgp_src) { + memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_src, sizeof(struct in_addr)); + pptrs->bgp_src = (char *) bgp_node_match_ipv4(rib[AFI_IP][SAFI_UNICAST], &pref4, (struct bgp_peer *) pptrs->bgp_peer); + } + if (!pptrs->bgp_src_info && pptrs->bgp_src) { + result = (struct bgp_node *) pptrs->bgp_src; + for (info = result->info[modulo]; info; info = info->next) { + if (info->peer == peer) { + pptrs->bgp_src_info = (char *) info; + break; + } + } + } + if (!pptrs->bgp_dst) { + memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); + pptrs->bgp_dst = (char *) bgp_node_match_ipv4(rib[AFI_IP][SAFI_UNICAST], &pref4, (struct bgp_peer *) pptrs->bgp_peer); + } + if (!pptrs->bgp_dst_info && pptrs->bgp_dst) { + result = (struct bgp_node *) pptrs->bgp_dst; + for (info = result->info[modulo]; info; info = info->next) { + if (info->peer == peer) { + pptrs->bgp_dst_info = (char *) info; + break; + } + } + } } #if defined ENABLE_IPV6 else if (pptrs->l3_proto == ETHERTYPE_IPV6) { - memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr)); - if (!pptrs->bgp_src) pptrs->bgp_src = (char *) bgp_node_match_ipv6(peer->rib[AFI_IP6][SAFI_UNICAST], &pref6); - memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); - if (!pptrs->bgp_dst) pptrs->bgp_dst = (char *) bgp_node_match_ipv6(peer->rib[AFI_IP6][SAFI_UNICAST], &pref6); + if (!pptrs->bgp_src) { + memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_src, sizeof(struct in6_addr)); + pptrs->bgp_src = (char *) bgp_node_match_ipv6(rib[AFI_IP6][SAFI_UNICAST], &pref6, (struct bgp_peer *) pptrs->bgp_peer); + } + if (!pptrs->bgp_src_info && pptrs->bgp_src) { + result = (struct bgp_node *) pptrs->bgp_src; + for (info = result->info[modulo]; info; info = info->next) { + if (info->peer == peer) { + pptrs->bgp_src_info = (char *) info; + break; + } + } + } + if (!pptrs->bgp_dst) { + memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); + pptrs->bgp_dst = (char *) bgp_node_match_ipv6(rib[AFI_IP6][SAFI_UNICAST], &pref6, (struct bgp_peer *) pptrs->bgp_peer); + } + if (!pptrs->bgp_dst_info && pptrs->bgp_dst) { + result = (struct bgp_node *) pptrs->bgp_dst; + for (info = result->info[modulo]; info; info = info->next) { + if (info->peer == peer) { + pptrs->bgp_dst_info = (char *) info; + break; + } + } + } } #endif @@ -1613,12 +1732,14 @@ if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_src = NULL; + pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; pptrs->bgp_dst = NULL; + pptrs->bgp_dst_info = NULL; } } #if defined ENABLE_IPV6 @@ -1629,23 +1750,25 @@ result = (struct bgp_node *) pptrs->bgp_src; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; + info = result->info[modulo]; pptrs->bgp_src = NULL; + pptrs->bgp_src_info = NULL; } result = (struct bgp_node *) pptrs->bgp_dst; if (result && prefix_match(&result->p, &default_prefix)) { default_node = result; + info = result->info[modulo]; pptrs->bgp_dst = NULL; + pptrs->bgp_dst_info = NULL; } } #endif if (!pptrs->bgp_src || !pptrs->bgp_dst) { follow_default--; - if (!saved_peer) saved_peer = peer; if (default_node) { - info = (struct bgp_info *) default_node->info; if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { sa = &sa_local; @@ -1677,17 +1800,15 @@ if (config.nfacctd_bgp_follow_nexthop[0].family && pptrs->bgp_dst) bgp_follow_nexthop_lookup(pptrs); } - - if (saved_peer) pptrs->bgp_peer = (char *) saved_peer; } void bgp_follow_nexthop_lookup(struct packet_ptrs *pptrs) { struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent, sa_local; - struct bgp_peer *nh_peer, *saved_peer = NULL; + struct bgp_peer *nh_peer; struct bgp_node *result_node = NULL; struct bgp_info *info; - char *result = NULL, *saved_result = NULL; + char *result = NULL, *saved_info = NULL; int peers_idx, ttl = MAX_HOPS_FOLLOW_NH, self = MAX_NH_SELF_REFERENCES; int nh_idx, matched = 0; struct prefix nh, ch; @@ -1697,6 +1818,7 @@ #endif char *saved_agent = pptrs->f_agent; pm_id_t bta; + u_int32_t modulo; start_again: @@ -1711,36 +1833,42 @@ } for (nh_peer = NULL, peers_idx = 0; peers_idx < config.nfacctd_bgp_max_peers; peers_idx++) { - if (!sa_addr_cmp(sa, &peers[peers_idx].addr)) { + if (!sa_addr_cmp(sa, &peers[peers_idx].addr) || !sa_addr_cmp(sa, &peers[peers_idx].id)) { nh_peer = &peers[peers_idx]; break; } } if (nh_peer) { + modulo = nh_peer->fd % config.bgp_table_peer_buckets; + memset(&ch, 0, sizeof(ch)); ch.family = AF_INET; ch.prefixlen = 32; memcpy(&ch.u.prefix4, &nh_peer->addr.address.ipv4, 4); - if (pptrs->l3_proto == ETHERTYPE_IP) { - memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); - result = (char *) bgp_node_match_ipv4(nh_peer->rib[AFI_IP][SAFI_UNICAST], &pref4); - } + if (!result) { + if (pptrs->l3_proto == ETHERTYPE_IP) { + memcpy(&pref4, &((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, sizeof(struct in_addr)); + result = (char *) bgp_node_match_ipv4(rib[AFI_IP][SAFI_UNICAST], &pref4, nh_peer); + } #if defined ENABLE_IPV6 - else if (pptrs->l3_proto == ETHERTYPE_IPV6) { - memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); - result = (char *) bgp_node_match_ipv6(nh_peer->rib[AFI_IP6][SAFI_UNICAST], &pref6); - } + else if (pptrs->l3_proto == ETHERTYPE_IPV6) { + memcpy(&pref6, &((struct ip6_hdr *)pptrs->iph_ptr)->ip6_dst, sizeof(struct in6_addr)); + result = (char *) bgp_node_match_ipv6(rib[AFI_IP6][SAFI_UNICAST], &pref6, nh_peer); + } #endif + } memset(&nh, 0, sizeof(nh)); result_node = (struct bgp_node *) result; - if (result_node) - info = (struct bgp_info *) result_node->info; - else - info = NULL; + if (result_node) { + for (info = result_node->info[modulo]; info; info = info->next) { + if (info->peer == nh_peer) break; + } + } + else info = NULL; if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { @@ -1760,7 +1888,7 @@ memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->mp_nexthop.address.ipv4, 4); - saved_result = result; + saved_info = (char *) info; ttl--; goto start_again; } @@ -1784,7 +1912,7 @@ memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET6; memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, &info->attr->mp_nexthop.address.ipv6, 16); - saved_result = result; + saved_info = (char *) info; ttl--; goto start_again; } @@ -1808,7 +1936,7 @@ memset(sa, 0, sizeof(struct sockaddr)); sa->sa_family = AF_INET; memcpy(&((struct sockaddr_in *)sa)->sin_addr, &info->attr->nexthop, 4); - saved_result = result; + saved_info = (char *) info; ttl--; goto start_again; } @@ -1819,7 +1947,7 @@ end: - if (saved_result) pptrs->bgp_nexthop = saved_result; + if (saved_info) pptrs->bgp_nexthop_info = saved_info; pptrs->f_agent = saved_agent; } @@ -1975,3 +2103,29 @@ c->data_type |= PIPE_TYPE_BGP; } } + +void process_bgp_md5_file(int sock, struct bgp_md5_table *bgp_md5) +{ + struct my_tcp_md5sig md5sig; + struct sockaddr_storage ss_md5sig; + int rc, keylen, idx = 0, ss_md5sig_len; + + while (idx < bgp_md5->num) { + memset(&md5sig, 0, sizeof(md5sig)); + memset(&ss_md5sig, 0, sizeof(ss_md5sig)); + + ss_md5sig_len = addr_to_sa((struct sockaddr *)&ss_md5sig, &bgp_md5->table[idx].addr, 0); + memcpy(&md5sig.tcpm_addr, &ss_md5sig, ss_md5sig_len); + + keylen = strlen(bgp_md5->table[idx].key); + if (keylen) { + md5sig.tcpm_keylen = keylen; + memcpy(md5sig.tcpm_key, &bgp_md5->table[idx].key, keylen); + } + + rc = setsockopt(sock, IPPROTO_TCP, TCP_MD5SIG, &md5sig, sizeof(md5sig)); + if (rc < 0) Log(LOG_ERR, "WARN ( default/core/BGP ): setsockopt() failed for TCP_MD5SIG (errno: %d).\n", errno); + + idx++; + } +} diff -Nru pmacct-0.12.1/src/bgp/bgp.h pmacct-0.12.5/src/bgp/bgp.h --- pmacct-0.12.1/src/bgp/bgp.h 2009-12-11 15:21:07.000000000 +0000 +++ pmacct-0.12.5/src/bgp/bgp.h 2010-08-10 17:49:53.000000000 +0000 @@ -101,7 +101,6 @@ u_int8_t cap_mp; char *cap_4as; u_int16_t msglen; - struct bgp_table *rib[AFI_MAX][SAFI_MAX]; struct bgp_peer_buf buf; }; @@ -161,8 +160,8 @@ EXT int bgp_process_withdraw(struct bgp_peer *, struct prefix *, void *, afi_t, safi_t); EXT int bgp_afi2family (int); EXT struct bgp_info *bgp_info_new(); -EXT void bgp_info_add(struct bgp_node *, struct bgp_info *); -EXT void bgp_info_delete(struct bgp_node *, struct bgp_info *); +EXT void bgp_info_add(struct bgp_node *, struct bgp_info *, u_int32_t); +EXT void bgp_info_delete(struct bgp_node *, struct bgp_info *, u_int32_t); EXT void bgp_info_free(struct bgp_info *); EXT void bgp_attr_init(); EXT struct bgp_attr *bgp_attr_intern(struct bgp_attr *); @@ -180,6 +179,7 @@ EXT void bgp_srcdst_lookup(struct packet_ptrs *); EXT void bgp_follow_nexthop_lookup(struct packet_ptrs *); EXT void write_neighbors_file(char *); +EXT void process_bgp_md5_file(int, struct bgp_md5_table *); EXT unsigned int attrhash_key_make(void *); EXT int attrhash_cmp(void *, void *); @@ -200,6 +200,7 @@ EXT char *std_comm_patterns_to_asn[MAX_BGP_COMM_PATTERNS]; EXT struct bgp_comm_range peer_src_as_ifrange; EXT struct bgp_comm_range peer_src_as_asrange; +EXT struct bgp_table *rib[AFI_MAX][SAFI_MAX]; #undef EXT #endif diff -Nru pmacct-0.12.1/src/bgp/bgp_packet.h pmacct-0.12.5/src/bgp/bgp_packet.h --- pmacct-0.12.1/src/bgp/bgp_packet.h 2009-03-09 14:40:25.000000000 +0000 +++ pmacct-0.12.5/src/bgp/bgp_packet.h 2010-06-30 11:08:05.000000000 +0000 @@ -3,7 +3,7 @@ * * Baselined from: * - * $Id: bgp_packet.h,v 1.1.1.1 2009/03/09 14:40:25 paolo Exp $ + * $Id: bgp_packet.h,v 1.2 2010/06/30 11:08:05 paolo Exp $ * * Wireshark - Network traffic analyzer * By Gerald Combs @@ -57,7 +57,7 @@ #define SAFI_UNICAST 1 #define SAFI_MULTICAST 2 #define SAFI_UNICAST_MULTICAST 3 -#define SAFI_MPLS_VPN 4 +#define SAFI_MPLS_LABEL 4 #define SAFI_MAX 5 struct bgp_header { diff -Nru pmacct-0.12.1/src/bgp/bgp_table.c pmacct-0.12.5/src/bgp/bgp_table.c --- pmacct-0.12.1/src/bgp/bgp_table.c 2009-04-28 13:33:05.000000000 +0000 +++ pmacct-0.12.5/src/bgp/bgp_table.c 2010-08-12 16:08:14.000000000 +0000 @@ -58,6 +58,10 @@ rn = (struct bgp_node *) malloc (sizeof (struct bgp_node)); memset (rn, 0, sizeof (struct bgp_node)); + + rn->info = (void **) malloc(sizeof(struct bgp_info *) * config.bgp_table_peer_buckets); + memset (rn->info, 0, sizeof(struct bgp_info *) * config.bgp_table_peer_buckets); + return rn; } @@ -79,6 +83,7 @@ static void bgp_node_free (struct bgp_node *node) { + free (node->info); free (node); } @@ -88,27 +93,31 @@ bgp_node_free_aggressive (struct bgp_node *node) { struct bgp_info *ri, *next; + u_int32_t ri_idx; - for (ri = node->info; ri; ri = next) { - if (config.nfacctd_bgp_msglog) { - char empty[] = ""; - char prefix_str[INET6_ADDRSTRLEN]; - char *aspath, *comm, *ecomm; + for (ri_idx = 0; ri_idx < config.bgp_table_peer_buckets; ri_idx++) { + for (ri = node->info[ri_idx]; ri; ri = next) { + if (config.nfacctd_bgp_msglog) { + char empty[] = ""; + char prefix_str[INET6_ADDRSTRLEN]; + char *aspath, *comm, *ecomm; + + memset(prefix_str, 0, INET6_ADDRSTRLEN); + prefix2str(&node->p, prefix_str, INET6_ADDRSTRLEN); + + aspath = ri->attr->aspath ? ri->attr->aspath->str : empty; + comm = ri->attr->community ? ri->attr->community->str : empty; + ecomm = ri->attr->ecommunity ? ri->attr->ecommunity->str : empty; - memset(prefix_str, 0, INET6_ADDRSTRLEN); - prefix2str(&node->p, prefix_str, INET6_ADDRSTRLEN); + Log(LOG_INFO, "INFO ( default/core/BGP ): d Prefix: %s Path: '%s' Comms: '%s' EComms: '%s'\n", prefix_str, aspath, comm, ecomm); + } - aspath = ri->attr->aspath ? ri->attr->aspath->str : empty; - comm = ri->attr->community ? ri->attr->community->str : empty; - ecomm = ri->attr->ecommunity ? ri->attr->ecommunity->str : empty; - - Log(LOG_INFO, "INFO ( default/core/BGP ): d Prefix: %s Path: '%s' Comms: '%s' EComms: '%s'\n", prefix_str, aspath, comm, ecomm); + next = ri->next; + bgp_info_free(ri); } - - next = ri->next; - bgp_info_free(ri); } + free (node->info); free (node); } @@ -258,33 +267,37 @@ /* Find matched prefix. */ struct bgp_node * -bgp_node_match (const struct bgp_table *table, struct prefix *p) +bgp_node_match (const struct bgp_table *table, struct prefix *p, struct bgp_peer *peer) { struct bgp_node *node; struct bgp_node *matched; + struct bgp_info *info; + u_int32_t modulo = peer->fd % config.bgp_table_peer_buckets; matched = NULL; node = table->top; /* Walk down tree. If there is matched route then store it to matched. */ - while (node && node->p.prefixlen <= p->prefixlen && - prefix_match (&node->p, p)) - { - if (node->info) + while (node && node->p.prefixlen <= p->prefixlen && prefix_match(&node->p, p)) { + for (info = node->info[modulo]; info; info = info->next) { + if (info->peer == peer) { matched = node; - node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + break; + } } + node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; + } + /* If matched route found, return it. */ - if (matched) - return bgp_lock_node (matched); + if (matched) return bgp_lock_node (matched); return NULL; } struct bgp_node * -bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr) +bgp_node_match_ipv4 (const struct bgp_table *table, struct in_addr *addr, struct bgp_peer *peer) { struct prefix_ipv4 p; @@ -293,12 +306,12 @@ p.prefixlen = IPV4_MAX_PREFIXLEN; p.prefix = *addr; - return bgp_node_match (table, (struct prefix *) &p); + return bgp_node_match (table, (struct prefix *) &p, peer); } #ifdef ENABLE_IPV6 struct bgp_node * -bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr) +bgp_node_match_ipv6 (const struct bgp_table *table, struct in6_addr *addr, struct bgp_peer *peer) { struct prefix_ipv6 p; @@ -307,30 +320,10 @@ p.prefixlen = IPV6_MAX_PREFIXLEN; p.prefix = *addr; - return bgp_node_match (table, (struct prefix *) &p); + return bgp_node_match (table, (struct prefix *) &p, peer); } #endif /* ENABLE_IPV6 */ -/* Lookup same prefix node. Return NULL when we can't find route. */ -struct bgp_node * -bgp_node_lookup (const struct bgp_table *table, struct prefix *p) -{ - struct bgp_node *node; - - node = table->top; - - while (node && node->p.prefixlen <= p->prefixlen && - prefix_match (&node->p, p)) - { - if (node->p.prefixlen == p->prefixlen && node->info) - return bgp_lock_node (node); - - node = node->link[check_bit(&p->u.prefix, node->p.prefixlen)]; - } - - return NULL; -} - /* Add node to routing table. */ struct bgp_node * bgp_node_get (struct bgp_table *const table, struct prefix *p) @@ -394,9 +387,11 @@ { struct bgp_node *child; struct bgp_node *parent; + u_int32_t ri_idx; assert (node->lock == 0); - assert (node->info == NULL); + for (ri_idx = 0; ri_idx < config.bgp_table_peer_buckets; ri_idx++) + assert (node->info[ri_idx] == NULL); if (node->l_left && node->l_right) return; diff -Nru pmacct-0.12.1/src/bgp/bgp_table.h pmacct-0.12.5/src/bgp/bgp_table.h --- pmacct-0.12.1/src/bgp/bgp_table.h 2009-07-30 12:41:26.000000000 +0000 +++ pmacct-0.12.5/src/bgp/bgp_table.h 2010-09-30 16:58:57.000000000 +0000 @@ -21,6 +21,8 @@ #ifndef _BGP_TABLE_H_ #define _BGP_TABLE_H_ +#define DEFAULT_BGP_INFO_HASH 13 + /* AFI and SAFI type. */ typedef u_int16_t afi_t; typedef u_int8_t safi_t; @@ -57,7 +59,7 @@ #define l_left link[0] #define l_right link[1] - void *info; + void **info; unsigned int lock; /* @@ -80,34 +82,6 @@ struct bgp_info *prev; struct bgp_peer *peer; struct bgp_attr *attr; - time_t uptime; - unsigned int lock; - - /* BGP information status. */ -/* - u_int16_t flags; -#define BGP_INFO_IGP_CHANGED (1 << 0) -#define BGP_INFO_DAMPED (1 << 1) -#define BGP_INFO_HISTORY (1 << 2) -#define BGP_INFO_SELECTED (1 << 3) -#define BGP_INFO_VALID (1 << 4) -#define BGP_INFO_ATTR_CHANGED (1 << 5) -#define BGP_INFO_DMED_CHECK (1 << 6) -#define BGP_INFO_DMED_SELECTED (1 << 7) -#define BGP_INFO_STALE (1 << 8) -#define BGP_INFO_REMOVED (1 << 9) -#define BGP_INFO_COUNTED (1 << 10) -*/ - - u_char type; - u_char sub_type; - u_char valid; - - /* MPLS label. */ -// u_char tag[3]; - - /* AS-Pathlimit TTL */ - u_char ttl; }; /* Prototypes */ @@ -123,14 +97,11 @@ EXT struct bgp_node *bgp_route_next (struct bgp_node *); EXT struct bgp_node *bgp_route_next_until (struct bgp_node *, struct bgp_node *); EXT struct bgp_node *bgp_node_get (struct bgp_table *const, struct prefix *); -EXT struct bgp_node *bgp_node_lookup (const struct bgp_table *const, struct prefix *); EXT struct bgp_node *bgp_lock_node (struct bgp_node *node); -EXT struct bgp_node *bgp_node_match (const struct bgp_table *, struct prefix *); -EXT struct bgp_node *bgp_node_match_ipv4 (const struct bgp_table *, - struct in_addr *); +EXT struct bgp_node *bgp_node_match (const struct bgp_table *, struct prefix *, struct bgp_peer *); +EXT struct bgp_node *bgp_node_match_ipv4 (const struct bgp_table *, struct in_addr *, struct bgp_peer *); #ifdef ENABLE_IPV6 -EXT struct bgp_node *bgp_node_match_ipv6 (const struct bgp_table *, - struct in6_addr *); +EXT struct bgp_node *bgp_node_match_ipv6 (const struct bgp_table *, struct in6_addr *, struct bgp_peer *); #endif /* ENABLE_IPV6 */ EXT unsigned long bgp_table_count (const struct bgp_table *const); diff -Nru pmacct-0.12.1/src/cfg.h pmacct-0.12.5/src/cfg.h --- pmacct-0.12.1/src/cfg.h 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/cfg.h 2010-10-31 22:51:41.000000000 +0000 @@ -87,6 +87,7 @@ int print_refresh_time; int print_cache_entries; int print_markers; + int print_output; int nfacctd_port; char *nfacctd_ip; char *nfacctd_allow_file; @@ -100,6 +101,7 @@ int nfacctd_bgp_msglog; char *nfacctd_bgp_ip; int nfacctd_bgp_port; + int nfacctd_bgp_ipprec; char *nfacctd_bgp_allow_file; int nfacctd_bgp_max_peers; int nfacctd_bgp_aspath_radius; @@ -121,6 +123,8 @@ int nfacctd_bgp_follow_default; struct prefix nfacctd_bgp_follow_nexthop[FOLLOW_BGP_NH_ENTRIES]; char *nfacctd_bgp_neighbors_file; + char *nfacctd_bgp_md5_file; + int bgp_table_peer_buckets; int promisc; /* pcap_open_live() promisc parameter */ char *clbuf; /* pcap filter */ char *pcap_savefile; @@ -165,12 +169,21 @@ char *nfprobe_engine; int nfprobe_peer_as; char *nfprobe_source_ip; + struct host_addr nfprobe_source_ha; + int nfprobe_ipprec; + int nfprobe_direction; + u_int32_t nfprobe_ifindex; + int nfprobe_ifindex_type; char *sfprobe_receiver; char *sfprobe_agentip; int sfprobe_agentsubid; + u_int64_t sfprobe_ifspeed; + int tee_transparent; int uacctd_group; int uacctd_nl_size; char *tunnel0; + int xlate_src; + int xlate_dst; }; struct plugin_type_entry { diff -Nru pmacct-0.12.1/src/cfg_handlers.c pmacct-0.12.5/src/cfg_handlers.c --- pmacct-0.12.1/src/cfg_handlers.c 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/cfg_handlers.c 2010-10-31 22:51:41.000000000 +0000 @@ -174,6 +174,7 @@ else if (!strcmp(count_token, "out_iface")) value |= COUNT_OUT_IFACE; else if (!strcmp(count_token, "src_mask")) value |= COUNT_SRC_NMASK; else if (!strcmp(count_token, "dst_mask")) value |= COUNT_DST_NMASK; + else if (!strcmp(count_token, "cos")) value |= COUNT_COS; else Log(LOG_WARNING, "WARN ( %s ): ignoring unknown aggregation method: %s.\n", filename, count_token); } @@ -249,7 +250,7 @@ trim_all_spaces(value_ptr); list->cfg.ptf.num = 0; - while ((count_token = extract_token(&value_ptr, ',')) && changes < MAX_MAP_ENTRIES/4) { + while ((count_token = extract_token(&value_ptr, ',')) && changes < MAX_PRETAG_MAP_ENTRIES/4) { neg = pt_check_neg(&count_token); range_ptr = pt_check_range(count_token); value = strtoul(count_token, &endptr_v, 10); @@ -295,7 +296,7 @@ trim_all_spaces(value_ptr); list->cfg.pt2f.num = 0; - while ((count_token = extract_token(&value_ptr, ',')) && changes < MAX_MAP_ENTRIES/4) { + while ((count_token = extract_token(&value_ptr, ',')) && changes < MAX_PRETAG_MAP_ENTRIES/4) { neg = pt_check_neg(&count_token); range_ptr = pt_check_range(count_token); value = strtoul(count_token, &endptr_v, 10); @@ -1484,6 +1485,34 @@ return changes; } +int cfg_key_print_output(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + if (!strcmp(value_ptr, "formatted")) + value = PRINT_OUTPUT_FORMATTED; + else if (!strcmp(value_ptr, "csv")) + value = PRINT_OUTPUT_CSV; + else { + Log(LOG_WARNING, "WARN ( %s ): Invalid print output value '%s'\n", filename, value_ptr); + return ERR; + } + + if (!name) for (; list; list = list->next, changes++) list->cfg.print_output = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.print_output = value; + changes++; + break; + } + } + } + + return changes; +} + int cfg_key_post_tag(char *filename, char *name, char *value_ptr) { struct plugins_list_entry *list = plugins_list; @@ -1585,6 +1614,17 @@ return changes; } +int cfg_key_nfacctd_bgp_md5_file(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int changes = 0; + + for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp_md5_file = value_ptr; + if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'bgp_daemon_md5_file'. Globalized.\n", filename); + + return changes; +} + int cfg_key_pre_tag_map(char *filename, char *name, char *value_ptr) { struct plugins_list_entry *list = plugins_list; @@ -1703,7 +1743,7 @@ value = parse_truefalse(value_ptr); if (value < 0) return ERR; - for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp = TRUE; + for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp = value; if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'bgp_daemon'. Globalized.\n", filename); return changes; @@ -1717,7 +1757,7 @@ value = parse_truefalse(value_ptr); if (value < 0) return ERR; - for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp_msglog = TRUE; + for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp_msglog = value; if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'bgp_daemon_msglog'. Globalized.\n", filename); return changes; @@ -2023,6 +2063,40 @@ return changes; } +int cfg_key_nfacctd_bgp_ip_precedence(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = atoi(value_ptr); + if ((value < 0) || (value > 7)) { + Log(LOG_ERR, "WARN ( %s ): 'bgp_daemon_ipprec' has to be in the range 0-7.\n", filename); + return ERR; + } + + for (; list; list = list->next, changes++) list->cfg.nfacctd_bgp_ipprec = value; + if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'bgp_daemon_ipprec'. Globalized.\n", filename); + + return changes; +} + +int cfg_key_nfacctd_bgp_table_peer_buckets(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = atoi(value_ptr); + if ((value <= 0) || (value > 1000)) { + Log(LOG_ERR, "WARN ( %s ): 'bgp_table_peer_buckets' has to be in the range 1-1000.\n", filename); + return ERR; + } + + for (; list; list = list->next, changes++) list->cfg.bgp_table_peer_buckets = value; + if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'bgp_table_peer_buckets'. Globalized.\n", filename); + + return changes; +} + int cfg_key_pmacctd_force_frag_handling(char *filename, char *name, char *value_ptr) { struct plugins_list_entry *list = plugins_list; @@ -2031,7 +2105,7 @@ value = parse_truefalse(value_ptr); if (value < 0) return ERR; - for (; list; list = list->next, changes++) list->cfg.handle_fragments = TRUE; + for (; list; list = list->next, changes++) list->cfg.handle_fragments = value; if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key 'pmacctd_force_frag_handling'. Globalized.\n", filename); return changes; @@ -2204,8 +2278,16 @@ return ERR; } - for (; list; list = list->next, changes++) list->cfg.nfacctd_net = value; - if (name) Log(LOG_WARNING, "WARN ( %s ): plugin name not supported for key '[nf|pm|sf|ua]acctd_net'. Globalized.\n", filename); + if (!name) for (; list; list = list->next, changes++) list->cfg.nfacctd_net = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.nfacctd_net = value; + changes++; + break; + } + } + } return changes; } @@ -2443,6 +2525,101 @@ return changes; } +int cfg_key_nfprobe_ip_precedence(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = atoi(value_ptr); + if ((value <= 0) || (value > 7)) { + Log(LOG_ERR, "WARN ( %s ): 'nfprobe_ipprec' and 'sfprobe_ipprec' have to be in the range 0-7.\n", filename); + return ERR; + } + + if (!name) for (; list; list = list->next, changes++) list->cfg.nfprobe_ipprec = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.nfprobe_ipprec = value; + changes++; + break; + } + } + } + + return changes; +} + +int cfg_key_nfprobe_direction(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + if (!strcmp(value_ptr, "tag")) + value = DIRECTION_TAG; + else if (!strcmp(value_ptr, "tag2")) + value = DIRECTION_TAG2; + else if (!strcmp(value_ptr, "in")) + value = DIRECTION_IN; + else if (!strcmp(value_ptr, "out")) + value = DIRECTION_OUT; + else { + Log(LOG_ERR, "WARN ( %s ): Invalid nfprobe_direction or sfprobe_direction value '%s'\n", filename, value_ptr); + return ERR; + } + + if (!name) { + Log(LOG_ERR, "ERROR ( %s ): nfprobe_direction and sfprobe_direction cannot be global. Not loaded.\n", filename); + changes++; + } + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.nfprobe_direction = value; + changes++; + break; + } + } + } + + return changes; +} + +int cfg_key_nfprobe_ifindex(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int changes = 0, value2 = 0; + u_int32_t value = 0; + + if (!strcmp(value_ptr, "tag")) + value2 = IFINDEX_TAG; + else if (!strcmp(value_ptr, "tag2")) + value2 = IFINDEX_TAG2; + else if (value = strtol(value_ptr, NULL, 0)) + value2 = IFINDEX_STATIC; + else { + Log(LOG_ERR, "WARN ( %s ): Invalid nfprobe_ifindex or sfprobe_ifindex value '%s'\n", filename, value_ptr); + return ERR; + } + + if (!name) { + Log(LOG_ERR, "ERROR ( %s ): nfprobe_ifindex and sfprobe_ifindex cannot be global. Not loaded.\n", filename); + changes++; + } + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.nfprobe_ifindex = value; + list->cfg.nfprobe_ifindex_type = value2; + changes++; + break; + } + } + } + + return changes; +} + int cfg_key_sfprobe_receiver(char *filename, char *name, char *value_ptr) { struct plugins_list_entry *list = plugins_list; @@ -2506,6 +2683,50 @@ return changes; } +int cfg_key_sfprobe_ifspeed(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int changes = 0; + u_int64_t value; + + value = strtoll(value_ptr, NULL, 0); + + if (!name) for (; list; list = list->next, changes++) list->cfg.sfprobe_ifspeed = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.sfprobe_ifspeed = value; + changes++; + break; + } + } + } + + return changes; +} + +int cfg_key_tee_transparent(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = parse_truefalse(value_ptr); + if (value < 0) return ERR; + + if (!name) for (; list; list = list->next, changes++) list->cfg.tee_transparent = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.tee_transparent = value; + changes++; + break; + } + } + } + + return changes; +} + void parse_time(char *filename, char *value, int *mu, int *howmany) { int k, j, len; @@ -2574,3 +2795,47 @@ return changes; } + +int cfg_key_xlate_src(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = parse_truefalse(value_ptr); + if (value < 0) return ERR; + + if (!name) for (; list; list = list->next, changes++) list->cfg.xlate_src = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.xlate_src = value; + changes++; + break; + } + } + } + + return changes; +} + +int cfg_key_xlate_dst(char *filename, char *name, char *value_ptr) +{ + struct plugins_list_entry *list = plugins_list; + int value, changes = 0; + + value = parse_truefalse(value_ptr); + if (value < 0) return ERR; + + if (!name) for (; list; list = list->next, changes++) list->cfg.xlate_dst = value; + else { + for (; list; list = list->next) { + if (!strcmp(name, list->name)) { + list->cfg.xlate_dst = value; + changes++; + break; + } + } + } + + return changes; +} diff -Nru pmacct-0.12.1/src/cfg_handlers.h pmacct-0.12.5/src/cfg_handlers.h --- pmacct-0.12.1/src/cfg_handlers.h 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/cfg_handlers.h 2010-10-31 22:51:41.000000000 +0000 @@ -86,6 +86,7 @@ EXT int cfg_key_print_refresh_time(char *, char *, char *); EXT int cfg_key_print_cache_entries(char *, char *, char *); EXT int cfg_key_print_markers(char *, char *, char *); +EXT int cfg_key_print_output(char *, char *, char *); EXT int cfg_key_nfacctd_port(char *, char *, char *); EXT int cfg_key_nfacctd_ip(char *, char *, char *); EXT int cfg_key_nfacctd_allow_file(char *, char *, char *); @@ -122,14 +123,20 @@ EXT int cfg_key_nfprobe_engine(char *, char *, char *); EXT int cfg_key_nfprobe_peer_as(char *, char *, char *); EXT int cfg_key_nfprobe_source_ip(char *, char *, char *); +EXT int cfg_key_nfprobe_ip_precedence(char *, char *, char *); +EXT int cfg_key_nfprobe_direction(char *, char *, char *); +EXT int cfg_key_nfprobe_ifindex(char *, char *, char *); EXT int cfg_key_sfprobe_receiver(char *, char *, char *); EXT int cfg_key_sfprobe_agentip(char *, char *, char *); EXT int cfg_key_sfprobe_agentsubid(char *, char *, char *); +EXT int cfg_key_sfprobe_ifspeed(char *, char *, char *); +EXT int cfg_key_tee_transparent(char *, char *, char *); EXT int cfg_key_nfacctd_bgp(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_msglog(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_max_peers(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_ip(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_port(char *, char *, char *); +EXT int cfg_key_nfacctd_bgp_ip_precedence(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_allow_file(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_aspath_radius(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_stdcomm_pattern(char *, char *, char *); @@ -150,9 +157,13 @@ EXT int cfg_key_nfacctd_bgp_follow_default(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_follow_nexthop(char *, char *, char *); EXT int cfg_key_nfacctd_bgp_neighbors_file(char *, char *, char *); +EXT int cfg_key_nfacctd_bgp_md5_file(char *, char *, char *); +EXT int cfg_key_nfacctd_bgp_table_peer_buckets(char *, char *, char *); EXT int cfg_key_uacctd_group(char *, char *, char *); EXT int cfg_key_uacctd_nl_size(char *, char *, char *); EXT int cfg_key_tunnel_0(char *, char *, char *); +EXT int cfg_key_xlate_src(char *, char *, char *); +EXT int cfg_key_xlate_dst(char *, char *, char *); EXT void parse_time(char *, char *, int *, int *); #undef EXT diff -Nru pmacct-0.12.1/src/classifier.c pmacct-0.12.5/src/classifier.c --- pmacct-0.12.1/src/classifier.c 2009-10-31 11:46:10.000000000 +0000 +++ pmacct-0.12.5/src/classifier.c 2010-10-23 21:47:25.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -64,6 +64,10 @@ class = map_shared(0, sizeof(struct pkt_classifier)*max, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); memset(class, 0, sizeof(struct pkt_classifier)*max); + /* valid case for nfacctd; NULL path checks are performed + in daemons requiring it - ie. pmacctd, uacctd, etc. */ + if (!path) return; + entries = pm_scandir(path, &namelist, 0, pm_alphasort); if (entries > 0) { while (n < entries) { @@ -102,16 +106,16 @@ } } -pm_class_t NF_evaluate_classifiers(char *string) +pm_class_t SF_evaluate_classifiers(char *string) { int j = 0, max = pmct_get_num_entries(); while (class[j].id && j < max) { - if ( !strcmp(class[j].protocol, string) ) return class[j].id; + if ( !strcmp(class[j].protocol, string) ) return class[j].id; j++; } - return 0; + return 0; } void evaluate_classifiers(struct packet_ptrs *pptrs, struct ip_flow_common *fp, unsigned int idx) @@ -631,10 +635,12 @@ pm_class_t pmct_find_first_free() { - int idx = 0, num = pmct_get_num_entries(); + int ret, idx = 0, num = pmct_get_num_entries(); while (idx < num) { - if ( pmct_isfree(idx+1) ) return idx+1; + ret = pmct_isfree(idx+1); + if (ret > 0) return idx+1; + else if (ret < 0) return 0; idx++; } @@ -643,11 +649,13 @@ pm_class_t pmct_find_last_free() { - int idx = pmct_get_num_entries(); + int ret, idx = pmct_get_num_entries(); idx--; while (idx) { - if ( pmct_isfree(idx+1) ) return idx+1; + ret = pmct_isfree(idx+1); + if (ret > 0) return idx+1; + else if (ret < 0) return 0; idx--; } @@ -658,6 +666,8 @@ { int max = pmct_get_num_entries(); + if (!class) return -1; + if (id && id <= max) { if (!class[id-1].id) return 1; else return 0; diff -Nru pmacct-0.12.1/src/classifier.h pmacct-0.12.5/src/classifier.h --- pmacct-0.12.1/src/classifier.h 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/src/classifier.h 2010-10-23 21:47:25.000000000 +0000 @@ -5,7 +5,6 @@ /* defines */ #define MAX_FN_LEN 256 #define MAX_SUBDIRS 128 -#define MAX_PROTOCOL_LEN 16 #define MAX_CLASSIFIERS 256 #define MAX_PATTERN_LEN 2048 #define DEFAULT_TENTATIVES 5 @@ -44,7 +43,7 @@ /* prototypes */ EXT void init_classifiers(char *); EXT void evaluate_classifiers(struct packet_ptrs *, struct ip_flow_common *, unsigned int); -EXT pm_class_t NF_evaluate_classifiers(char *); +EXT pm_class_t SF_evaluate_classifiers(char *); EXT int parse_pattern_file(char *, struct pkt_classifier *); EXT int parse_shared_object(char *, struct pkt_classifier *); EXT int dot_pat(char *); diff -Nru pmacct-0.12.1/src/conntrack.h pmacct-0.12.5/src/conntrack.h --- pmacct-0.12.1/src/conntrack.h 2008-07-16 22:38:42.000000000 +0000 +++ pmacct-0.12.5/src/conntrack.h 2010-10-23 21:47:25.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -20,7 +20,6 @@ */ /* defines */ -#define MAX_PROTOCOL_LEN 16 /* same as classifier.h */ #define CONNTRACK_GENERIC_LIFETIME 20 #define DEFAULT_CONNTRACK_BUFFER_SIZE 8192000 /* 8 Mb */ #define MAX_CONNTRACKS 256 diff -Nru pmacct-0.12.1/src/imt_plugin.h pmacct-0.12.5/src/imt_plugin.h --- pmacct-0.12.1/src/imt_plugin.h 2009-12-05 18:48:47.000000000 +0000 +++ pmacct-0.12.5/src/imt_plugin.h 2010-10-23 21:47:25.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -26,7 +26,6 @@ #define MEMORY_POOL_SIZE 8192 #define MAX_HOSTS 32771 #define MAX_QUERIES 4096 -#define MAX_PROTOCOL_LEN 16 /* same as classifier.h */ /* Structures */ struct acc { diff -Nru pmacct-0.12.1/src/ip_frag.c pmacct-0.12.5/src/ip_frag.c --- pmacct-0.12.1/src/ip_frag.c 2009-10-16 13:24:09.000000000 +0000 +++ pmacct-0.12.5/src/ip_frag.c 2010-05-05 15:30:32.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -277,7 +277,7 @@ memcpy(&a.address.ipv4, &frag->ip_dst, 4); addr_to_str(dst_host, &a); id = ntohs(frag->ip_id); - Log(LOG_INFO, "Expiring orphan fragment: ip_src=%s ip_dst=%s proto=%u id=%u\n", + Log(LOG_DEBUG, "DEBUG ( default/core ): Expiring orphan fragment: ip_src=%s ip_dst=%s proto=%u id=%u\n", src_host, dst_host, frag->ip_p, id); } @@ -531,6 +531,6 @@ ip6_addr_cpy(&a.address.ipv6, &frag->dst); addr_to_str(dst_host, &a); id = ntohl(frag->id); - Log(LOG_INFO, "Expiring orphan fragment: ip_src=%s ip_dst=%s id=%u\n", src_host, dst_host, id); + Log(LOG_DEBUG, "DEBUG ( default/core ): Expiring orphan fragment: ip_src=%s ip_dst=%s id=%u\n", src_host, dst_host, id); } #endif diff -Nru pmacct-0.12.1/src/ll.c pmacct-0.12.5/src/ll.c --- pmacct-0.12.1/src/ll.c 2008-07-16 22:38:43.000000000 +0000 +++ pmacct-0.12.5/src/ll.c 2010-04-27 19:25:58.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -34,6 +34,7 @@ u_int16_t e8021Q, ppp; struct eth_header *eth_pk; u_int16_t etype, caplen = h->caplen, nl; + u_int8_t cursor = 0; if (caplen < ETHER_HDRLEN) { pptrs->iph_ptr = NULL; @@ -71,10 +72,11 @@ return; } memcpy(&e8021Q, pptrs->packet_ptr+nl+2, 2); - pptrs->vlan_ptr = pptrs->packet_ptr + nl; + if (!cursor) pptrs->vlan_ptr = pptrs->packet_ptr + nl; etype = ntohs(e8021Q); nl += IEEE8021Q_TAGLEN; caplen -= IEEE8021Q_TAGLEN; + cursor++; goto recurse; } @@ -92,11 +94,13 @@ #endif nl += PPPOE_HDRLEN+PPP_TAGLEN; caplen -= PPPOE_HDRLEN+PPP_TAGLEN; + cursor = 1; goto recurse; } if (etype == ETHERTYPE_MPLS || etype == ETHERTYPE_MPLS_MULTI) { etype = mpls_handler(pptrs->packet_ptr + nl, &caplen, &nl, pptrs); + cursor = 1; goto recurse; } diff -Nru pmacct-0.12.1/src/Makefile.am pmacct-0.12.5/src/Makefile.am --- pmacct-0.12.1/src/Makefile.am 2009-10-25 15:18:00.000000000 +0000 +++ pmacct-0.12.5/src/Makefile.am 2010-05-04 11:20:38.000000000 +0000 @@ -1,4 +1,4 @@ -SUBDIRS = nfprobe_plugin sfprobe_plugin bgp +SUBDIRS = nfprobe_plugin sfprobe_plugin bgp tee_plugin sbin_PROGRAMS = pmacctd nfacctd sfacctd uacctd bin_PROGRAMS = pmacct @EXTRABIN@ EXTRA_PROGRAMS = pmmyplay pmpgplay diff -Nru pmacct-0.12.1/src/Makefile.in pmacct-0.12.5/src/Makefile.in --- pmacct-0.12.1/src/Makefile.in 2010-04-07 06:35:55.000000000 +0000 +++ pmacct-0.12.5/src/Makefile.in 2010-12-28 16:26:24.000000000 +0000 @@ -67,7 +67,7 @@ THREADS_SOURCES = @THREADS_SOURCES@ VERSION = @VERSION@ -SUBDIRS = nfprobe_plugin sfprobe_plugin bgp +SUBDIRS = nfprobe_plugin sfprobe_plugin bgp tee_plugin sbin_PROGRAMS = pmacctd nfacctd sfacctd uacctd bin_PROGRAMS = pmacct @EXTRABIN@ EXTRA_PROGRAMS = pmmyplay pmpgplay diff -Nru pmacct-0.12.1/src/mysql_plugin.c pmacct-0.12.5/src/mysql_plugin.c --- pmacct-0.12.1/src/mysql_plugin.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/mysql_plugin.c 2010-10-06 07:26:12.000000000 +0000 @@ -626,9 +626,11 @@ { if (!db->fail) { if (mysql_query(db->desc, buf)) { - Log(LOG_DEBUG, "DEBUG ( %s/%s ): FAILED query follows:\n%s\n", config.name, config.type, buf); - MY_get_errmsg(db); - sql_db_errmsg(db); + if (mysql_errno(db->desc) != 1050 /* ER_TABLE_EXISTS_ERROR */) { + Log(LOG_DEBUG, "DEBUG ( %s/%s ): FAILED query follows:\n%s\n", config.name, config.type, buf); + MY_get_errmsg(db); + sql_db_errmsg(db); + } } } } @@ -666,6 +668,7 @@ if (!config.sql_passwd) config.sql_passwd = mysql_pwd; if (!config.sql_table) { if (config.sql_table_version == (SQL_TABLE_VERSION_BGP+1)) config.sql_table = mysql_table_bgp; + else if (config.sql_table_version == 8) config.sql_table = mysql_table_v8; else if (config.sql_table_version == 7) config.sql_table = mysql_table_v7; else if (config.sql_table_version == 6) config.sql_table = mysql_table_v6; else if (config.sql_table_version == 5) config.sql_table = mysql_table_v5; diff -Nru pmacct-0.12.1/src/mysql_plugin.h pmacct-0.12.5/src/mysql_plugin.h --- pmacct-0.12.1/src/mysql_plugin.h 2009-07-05 12:10:14.000000000 +0000 +++ pmacct-0.12.5/src/mysql_plugin.h 2010-10-06 07:26:12.000000000 +0000 @@ -53,4 +53,5 @@ static char mysql_table_v5[] = "acct_v5"; static char mysql_table_v6[] = "acct_v6"; static char mysql_table_v7[] = "acct_v7"; +static char mysql_table_v8[] = "acct_v8"; static char mysql_table_bgp[] = "acct_bgp"; diff -Nru pmacct-0.12.1/src/network.h pmacct-0.12.5/src/network.h --- pmacct-0.12.1/src/network.h 2010-03-12 00:09:17.000000000 +0000 +++ pmacct-0.12.5/src/network.h 2010-10-03 20:28:31.000000000 +0000 @@ -36,6 +36,7 @@ #define ETHER_HDRLEN 14 #define ETHERMTU 1500 #define IEEE8021Q_TAGLEN 4 +#define IEEE8021AH_LEN 10 #define PPP_TAGLEN 2 #define MAX_MCAST_GROUPS 20 #define ROUTING_SEGMENT_MAX 16 @@ -69,6 +70,7 @@ #define ETHERTYPE_8021Q 0x8100 /* 802.1Q */ #define ETHERTYPE_MPLS 0x8847 /* MPLS */ #define ETHERTYPE_MPLS_MULTI 0x8848 /* MPLS */ +#define ETHERTYPE_8021AH 0x88A8 /* 802.1ah */ /* PPP protocol definitions */ #define PPP_HDRLEN 4 /* octets for standard ppp header */ @@ -161,6 +163,24 @@ u_int16_t th_urp; /* urgent pointer */ }; +/* For TCP_MD5SIG socket option. */ +#ifndef TCP_MD5SIG_MAXKEYLEN +#define TCP_MD5SIG_MAXKEYLEN 80 +#endif + +#ifndef TCP_MD5SIG +#define TCP_MD5SIG 14 +#endif + +struct my_tcp_md5sig +{ + struct sockaddr_storage tcpm_addr; /* Address associated. */ + u_int16_t __tcpm_pad1; /* Zero. */ + u_int16_t tcpm_keylen; /* Key length. */ + u_int32_t __tcpm_pad2; /* Zero. */ + u_int8_t tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* Key (binary). */ +}; + struct my_udphdr { u_int16_t uh_sport; /* source port */ @@ -169,6 +189,27 @@ u_int16_t uh_sum; /* udp checksum */ }; +struct my_icmphdr +{ + u_int8_t type; /* message type */ + u_int8_t code; /* type sub-code */ + u_int16_t checksum; + union + { + struct + { + u_int16_t id; + u_int16_t sequence; + } echo; /* echo datagram */ + u_int32_t gateway; /* gateway address */ + struct + { + u_int16_t __unused; + u_int16_t mtu; + } frag; /* path mtu discovery */ + } un; +}; + struct my_tlhdr { u_int16_t src_port; /* source and destination ports */ u_int16_t dst_port; @@ -221,8 +262,10 @@ pm_id_t bta; /* bgp_to_agent */ char *bgp_src; /* pointer to bgp_node structure for source prefix, if any */ char *bgp_dst; /* pointer to bgp_node structure for destination prefix, if any */ + char *bgp_src_info; /* pointer to bgp_info structure for source prefix, if any */ + char *bgp_dst_info; /* pointer to bgp_info structure for destination prefix, if any */ char *bgp_peer; /* record BGP peer's Router-ID */ - char *bgp_nexthop; /* record BGP next-hop in case of follow-up */ + char *bgp_nexthop_info; /* record bgp_info of BGP next-hop in case of follow-up */ u_int16_t pf; /* pending fragments or packets */ u_int8_t new_flow; /* pmacctd flows: part of a new flow ? */ u_int8_t tcp_flags; /* pmacctd flows: TCP packet flags; URG, PUSH filtered out */ @@ -239,6 +282,8 @@ u_int16_t ifindex_out; /* output ifindex; only used by ULOG for the time being */ u_int8_t tun_stack; /* tunnelling stack */ u_int8_t tun_layer; /* tunnelling layer count */ + u_int32_t seqno; /* sFlow/NetFlow sequence number */ + u_int16_t f_len; /* sFlow/NetFlow payload length */ }; struct host_addr { @@ -256,6 +301,7 @@ u_int8_t eth_dhost[ETH_ADDR_LEN]; u_int8_t eth_shost[ETH_ADDR_LEN]; u_int16_t vlan_id; + u_int8_t cos; #endif struct host_addr src_ip; struct host_addr dst_ip; @@ -302,11 +348,24 @@ u_int16_t ifindex_out; u_int8_t src_nmask; u_int8_t dst_nmask; + u_int16_t vlan; + u_int8_t priority; + struct host_addr bgp_next_hop; }; struct pkt_extras { u_int8_t tcp_flags; u_int32_t mpls_top_label; + struct host_addr bgp_next_hop; +}; + +#define PKT_MSG_SIZE 1550 +struct pkt_msg { + struct sockaddr agent; + u_int32_t seqno; + u_int16_t len; + u_char payload[PKT_MSG_SIZE]; + u_int16_t pad; }; /* START: BGP section */ @@ -330,6 +389,7 @@ u_int32_t src_local_pref; u_int32_t src_med; u_int32_t is_symmetric; + u_int32_t pad; }; /* same as above but pointers in place of strings */ @@ -370,6 +430,16 @@ struct host_addr table[MAX_MAP_ENTRIES]; }; +struct bgp_md5_table_entry { + struct host_addr addr; + char key[TCP_MD5SIG_MAXKEYLEN]; +}; + +struct bgp_md5_table { + short int num; + struct bgp_md5_table_entry table[BGP_MD5_MAP_ENTRIES]; +}; + #define TUNNEL_PROTO_STRING 16 #define TUNNEL_REGISTRY_STACKS 9 /* MAX + 1 */ #define TUNNEL_REGISTRY_ENTRIES 4 diff -Nru pmacct-0.12.1/src/nfacctd.c pmacct-0.12.5/src/nfacctd.c --- pmacct-0.12.1/src/nfacctd.c 2010-03-06 12:10:16.000000000 +0000 +++ pmacct-0.12.5/src/nfacctd.c 2010-12-07 21:41:06.000000000 +0000 @@ -55,23 +55,26 @@ printf(" -L \tBind to the specified IP address\n"); printf(" -l \tListen on the specified UDP port\n"); printf(" -f \tLoad configuration from the specified file\n"); - printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | none ] \n\tAggregation string (DEFAULT: src_host)\n"); + printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | cos | none ] \n\tAggregation string (DEFAULT: src_host)\n"); printf(" -D \tDaemonize\n"); printf(" -n \tPath to a file containing Network definitions\n"); printf(" -o \tPath to a file containing Port definitions\n"); - printf(" -P \t[ memory | print | mysql | pgsql | sqlite3 | nfprobe ] \n\tActivate plugin\n"); + printf(" -P \t[ memory | print | mysql | pgsql | sqlite3 | tee ] \n\tActivate plugin\n"); printf(" -d \tEnable debug\n"); printf(" -S \t[ auth | mail | daemon | kern | user | local[0-7] ] \n\tLog to the specified syslog facility\n"); printf(" -F \tWrite Core Process PID into the specified file\n"); printf(" -R \tRenormalize sampled data\n"); - printf("\nMemory Plugin (-P memory) options:\n"); + printf("\nMemory plugin (-P memory) options:\n"); printf(" -p \tSocket for client-server communication (DEFAULT: /tmp/collect.pipe)\n"); printf(" -b \tNumber of buckets\n"); printf(" -m \tNumber of memory pools\n"); printf(" -s \tMemory pool size\n"); printf("\nPostgreSQL (-P pgsql)/MySQL (-P mysql)/SQLite (-P sqlite3) plugin options:\n"); printf(" -r \tRefresh time (in seconds)\n"); - printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] \n\tTable version\n"); + printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] \n\tTable version\n"); + printf("\nPrint plugin (-P print) plugin options:\n"); + printf(" -r \tRefresh time (in seconds)\n"); + printf(" -O \t[ formatted | csv ] \n\tOutput format\n"); printf("\n"); printf(" See EXAMPLES or visit http://wiki.pmacct.net/ for examples.\n"); printf("\n"); @@ -146,6 +149,8 @@ bta_map_allocated = FALSE; find_id_func = NF_find_id; + data_plugins = 0; + tee_plugins = 0; xflow_status_table_entries = 0; xflow_tot_bad_datagrams = 0; errflag = 0; @@ -209,6 +214,11 @@ strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; + case 'O': + strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN); + strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); + rows++; + break; case 'f': strlcpy(config_file, optarg, sizeof(config_file)); break; @@ -334,86 +344,21 @@ /* Enforcing policies over aggregation methods */ list = plugins_list; while (list) { - if (list->type.id != PLUGIN_ID_CORE) { + if (list->type.id != PLUGIN_ID_CORE) { /* applies to all plugins */ if (list->cfg.sampling_rate && config.ext_sampling_rate) { Log(LOG_ERR, "ERROR: Internal packet sampling and external packet sampling are mutual exclusive.\n"); exit(1); } - if (list->type.id == PLUGIN_ID_NFPROBE) { - /* If we already renormalizing an external sampling rate, - we cancel the sampling information from the probe plugin */ - if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; - - list->cfg.nfprobe_what_to_count = list->cfg.what_to_count; - list->cfg.what_to_count = 0; -#if defined (HAVE_L2) - if (list->cfg.nfprobe_version == 9) { - list->cfg.what_to_count |= COUNT_SRC_MAC; - list->cfg.what_to_count |= COUNT_DST_MAC; - list->cfg.what_to_count |= COUNT_VLAN; - } -#endif - list->cfg.what_to_count |= COUNT_SRC_HOST; - list->cfg.what_to_count |= COUNT_DST_HOST; - - if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) { - list->cfg.what_to_count |= COUNT_SRC_NMASK; - list->cfg.what_to_count |= COUNT_DST_NMASK; - } - - list->cfg.what_to_count |= COUNT_SRC_PORT; - list->cfg.what_to_count |= COUNT_DST_PORT; - list->cfg.what_to_count |= COUNT_IP_TOS; - list->cfg.what_to_count |= COUNT_IP_PROTO; - if (list->cfg.networks_file || list->cfg.nfacctd_as == NF_AS_KEEP || - list->cfg.nfacctd_as == NF_AS_BGP) { - list->cfg.what_to_count |= COUNT_SRC_AS; - list->cfg.what_to_count |= COUNT_DST_AS; - } - if (list->cfg.nfprobe_version == 9 && list->cfg.classifiers_path) - list->cfg.what_to_count |= COUNT_CLASS; - if (list->cfg.nfprobe_version == 9 && list->cfg.pre_tag_map) { - list->cfg.what_to_count |= COUNT_ID; - list->cfg.what_to_count |= COUNT_ID2; - } - list->cfg.what_to_count |= COUNT_IN_IFACE; - list->cfg.what_to_count |= COUNT_OUT_IFACE; - if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); - exit(1); - } - if (list->cfg.nfprobe_version == 9) - list->cfg.what_to_count |= COUNT_FLOWS; - list->cfg.what_to_count |= COUNT_COUNTERS; - list->cfg.data_type = PIPE_TYPE_METADATA; - list->cfg.data_type |= PIPE_TYPE_EXTRAS; + if (list->type.id == PLUGIN_ID_NFPROBE || list->type.id == PLUGIN_ID_SFPROBE) { + Log(LOG_ERR, "ERROR: 'nfprobe' and 'sfprobe' plugins not supported in 'nfacctd'.\n"); + exit(1); } - else if (list->type.id == PLUGIN_ID_SFPROBE) { - /* If we already renormalizing an external sampling rate, - we cancel the sampling information from the probe plugin */ - if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; - - req.bpf_filter = TRUE; - list->cfg.what_to_count = COUNT_PAYLOAD; - if (list->cfg.classifiers_path) list->cfg.what_to_count |= COUNT_CLASS; - if (list->cfg.pre_tag_map) { - list->cfg.what_to_count |= COUNT_ID; - list->cfg.what_to_count |= COUNT_ID2; - } - if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); - exit(1); - } - - list->cfg.data_type = PIPE_TYPE_PAYLOAD; + else if (list->type.id == PLUGIN_ID_TEE) { + tee_plugins++; + list->cfg.what_to_count = COUNT_NONE; + list->cfg.data_type = PIPE_TYPE_MSG; } else { list->cfg.data_type = PIPE_TYPE_METADATA; @@ -434,10 +379,7 @@ if (!list->cfg.nfacctd_net) { if (list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; if (list->cfg.networks_mask) list->cfg.nfacctd_net |= NF_NET_STATIC; - if (!list->cfg.nfacctd_net) { - Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'nfacctd_net', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string); - exit(1); - } + if (!list->cfg.nfacctd_net) list->cfg.nfacctd_net = NF_NET_KEEP; } else { if ((list->cfg.nfacctd_net == NF_NET_NEW && !list->cfg.networks_file) || @@ -448,19 +390,21 @@ } } } - if (list->cfg.what_to_count & COUNT_CLASS && !list->cfg.classifiers_path) { - Log(LOG_ERR, "ERROR ( %s/%s ): 'class' aggregation selected but NO 'classifiers' key specified. Exiting...\n\n", list->name, list->type.string); - exit(1); - } bgp_config_checks(&list->cfg); + data_plugins++; list->cfg.what_to_count |= COUNT_COUNTERS; } } list = list->next; } + if (tee_plugins && data_plugins) { + Log(LOG_ERR, "ERROR: 'tee' plugins are not compatible with data (memory/mysql/pgsql/etc.) plugins. Exiting...\n\n"); + exit(1); + } + /* signal handling we want to inherit to plugins (when not re-defined elsewhere) */ signal(SIGCHLD, startup_handle_falling_child); /* takes note of plugins failed during startup phase */ signal(SIGHUP, reload); /* handles reopening of syslog channel */ @@ -620,7 +564,7 @@ load_nfv8_handlers(); - if (config.classifiers_path) init_classifiers(config.classifiers_path); + init_classifiers(NULL); /* plugins glue: creation */ load_plugins(&req); @@ -786,6 +730,8 @@ if (ret < 1) continue; /* we don't have enough data to decode the version */ + pptrs.v4.f_len = ret; + /* check if Hosts Allow Table is loaded; if it is, we will enforce rules */ if (allow.num) allowed = check_allow(&allow, (struct sockaddr *)&client); if (!allowed) continue; @@ -807,31 +753,36 @@ reload_map = FALSE; } - /* We will change byte ordering in order to avoid a bunch of ntohs() calls */ - ((struct struct_header_v5 *)netflow_packet)->version = ntohs(((struct struct_header_v5 *)netflow_packet)->version); - reset_tag_status(&pptrs); - reset_shadow_status(&pptrs); + if (data_plugins) { + /* We will change byte ordering in order to avoid a bunch of ntohs() calls */ + ((struct struct_header_v5 *)netflow_packet)->version = ntohs(((struct struct_header_v5 *)netflow_packet)->version); + reset_tag_status(&pptrs); + reset_shadow_status(&pptrs); - switch(((struct struct_header_v5 *)netflow_packet)->version) { - case 1: - process_v1_packet(netflow_packet, ret, &pptrs.v4, &req); - break; - case 5: - process_v5_packet(netflow_packet, ret, &pptrs.v4, &req); - break; - case 7: - process_v7_packet(netflow_packet, ret, &pptrs.v4, &req); - break; - case 8: - process_v8_packet(netflow_packet, ret, &pptrs.v4, &req); - break; - case 9: - process_v9_packet(netflow_packet, ret, &pptrs, &req); - break; - default: - notify_malf_packet(LOG_INFO, "INFO: Discarding unknown packet", (struct sockaddr *) pptrs.v4.f_agent); - xflow_tot_bad_datagrams++; - break; + switch(((struct struct_header_v5 *)netflow_packet)->version) { + case 1: + process_v1_packet(netflow_packet, ret, &pptrs.v4, &req); + break; + case 5: + process_v5_packet(netflow_packet, ret, &pptrs.v4, &req); + break; + case 7: + process_v7_packet(netflow_packet, ret, &pptrs.v4, &req); + break; + case 8: + process_v8_packet(netflow_packet, ret, &pptrs.v4, &req); + break; + case 9: + process_v9_packet(netflow_packet, ret, &pptrs, &req); + break; + default: + notify_malf_packet(LOG_INFO, "INFO: Discarding unknown packet", (struct sockaddr *) pptrs.v4.f_agent); + xflow_tot_bad_datagrams++; + break; + } + } + else if (tee_plugins) { + process_raw_packet(netflow_packet, ret, &pptrs, &req); } } } @@ -917,6 +868,7 @@ Assign8(((struct my_iphdr *)pptrs->iph_ptr)->ip_tos, exp_v5->tos); Assign16(((struct my_tlhdr *)pptrs->tlh_ptr)->src_port, exp_v5->srcport); Assign16(((struct my_tlhdr *)pptrs->tlh_ptr)->dst_port, exp_v5->dstport); + Assign8(((struct my_tcphdr *)pptrs->tlh_ptr)->th_flags, exp_v5->tcp_flags); } /* Let's copy some relevant field */ pptrs->l4_proto = exp_v5->prot; @@ -970,6 +922,7 @@ Assign8(((struct my_iphdr *)pptrs->iph_ptr)->ip_tos, exp_v7->tos); Assign16(((struct my_tlhdr *)pptrs->tlh_ptr)->src_port, exp_v7->srcport); Assign16(((struct my_tlhdr *)pptrs->tlh_ptr)->dst_port, exp_v7->dstport); + Assign8(((struct my_tcphdr *)pptrs->tlh_ptr)->th_flags, exp_v7->tcp_flags); } /* Let's copy some relevant field */ pptrs->l4_proto = exp_v7->prot; @@ -1048,7 +1001,7 @@ struct template_cache_entry *tpl; struct data_hdr_v9 *data_hdr; struct packet_ptrs *pptrs = &pptrsv->v4; - u_int16_t fid, off = 0, flowoff, flowsetlen, flow_type; + u_int16_t fid, off = 0, flowoff, flowsetlen, flow_type, direction; if (len < NfHdrV9Sz) { notify_malf_packet(LOG_INFO, "INFO: discarding short NetFlow v9 packet", (struct sockaddr *) pptrsv->v4.f_agent); @@ -1152,24 +1105,60 @@ } else if (tpl->template_type == 1) { /* Options coming */ struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; - struct xflow_status_entry_sampling *sentry, *saved = NULL; - u_int8_t sampler_id = 0; + struct xflow_status_entry_sampling *sentry = NULL, *ssaved = NULL; + struct xflow_status_entry_class *centry = NULL, *csaved = NULL; while (flowoff+tpl->len <= flowsetlen) { - if (tpl->tpl[NF9_FLOW_SAMPLER_ID].len == 1) + /* Is this option about sampling? */ + if (tpl->tpl[NF9_FLOW_SAMPLER_ID].len == 1) { + u_int8_t sampler_id = 0; + memcpy(&sampler_id, pkt+tpl->tpl[NF9_FLOW_SAMPLER_ID].off, 1); - sentry = search_smp_id_status_table(entry->sampling, sampler_id); - if (!sentry) sentry = create_smp_entry_status_table(entry); - else saved = sentry->next; - - if (sentry) { - memset(sentry, 0, sizeof(struct xflow_status_entry_sampling)); - if (tpl->tpl[NF9_SAMPLING_INTERVAL].len == 4) memcpy(&sentry->sample_pool, pkt+tpl->tpl[NF9_SAMPLING_INTERVAL].off, 4); - if (tpl->tpl[NF9_FLOW_SAMPLER_INTERVAL].len == 4) memcpy(&sentry->sample_pool, pkt+tpl->tpl[NF9_FLOW_SAMPLER_INTERVAL].off, 4); - sentry->sampler_id = sampler_id; - sentry->sample_pool = ntohl(sentry->sample_pool); - if (saved) sentry->next = saved; + if (entry) sentry = search_smp_id_status_table(entry->sampling, sampler_id); + if (!sentry) sentry = create_smp_entry_status_table(entry); + else ssaved = sentry->next; + + if (sentry) { + memset(sentry, 0, sizeof(struct xflow_status_entry_sampling)); + if (tpl->tpl[NF9_SAMPLING_INTERVAL].len == 4) memcpy(&sentry->sample_pool, pkt+tpl->tpl[NF9_SAMPLING_INTERVAL].off, 4); + if (tpl->tpl[NF9_FLOW_SAMPLER_INTERVAL].len == 4) memcpy(&sentry->sample_pool, pkt+tpl->tpl[NF9_FLOW_SAMPLER_INTERVAL].off, 4); + sentry->sampler_id = sampler_id; + sentry->sample_pool = ntohl(sentry->sample_pool); + if (ssaved) sentry->next = ssaved; + } + } + else if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct pkt_classifier css; + pm_class_t class_id = 0, class_int_id = 0; + + memcpy(&class_id, pkt+tpl->tpl[NF9_APPLICATION_ID].off, 4); + + if (entry) centry = search_class_id_status_table(entry->class, class_id); + if (!centry) { + centry = create_class_entry_status_table(entry); + class_int_id = pmct_find_first_free(); + } + else { + csaved = centry->next; + class_int_id = centry->class_int_id; + pmct_unregister(centry->class_int_id); + } + + if (centry) { + memset(centry, 0, sizeof(struct xflow_status_entry_class)); + memset(&css, 0, sizeof(struct pkt_classifier)); + + if (tpl->tpl[NF9_APPLICATION_NAME].len > 0) + memcpy(¢ry->class_name, pkt+tpl->tpl[NF9_APPLICATION_NAME].off, MIN((MAX_PROTOCOL_LEN-1), tpl->tpl[NF9_APPLICATION_NAME].len)); + centry->class_id = class_id; + centry->class_int_id = class_int_id; + if (csaved) centry->next = csaved; + + css.id = centry->class_int_id; + strlcpy(css.protocol, centry->class_name, MAX_PROTOCOL_LEN); + pmct_register(&css); + } } pkt += tpl->len; @@ -1184,6 +1173,7 @@ pptrs->f_data = pkt; pptrs->f_tpl = (u_char *) tpl; flow_type = NF_evaluate_flow_type(tpl, pptrs); + direction = NF_evaluate_direction(tpl, pptrs); /* we need to understand the IP protocol version in order to build the fake packet */ switch (flow_type) { @@ -1192,8 +1182,14 @@ reset_mac(pptrs); reset_ip4(pptrs); - memcpy(pptrs->mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrs->mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); + if (direction == DIRECTION_IN) { + memcpy(pptrs->mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrs->mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrs->mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrs->mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + } ((struct my_iphdr *)pptrs->iph_ptr)->ip_vhl = 0x45; memcpy(&((struct my_iphdr *)pptrs->iph_ptr)->ip_src, pkt+tpl->tpl[NF9_IPV4_SRC_ADDR].off, tpl->tpl[NF9_IPV4_SRC_ADDR].len); memcpy(&((struct my_iphdr *)pptrs->iph_ptr)->ip_dst, pkt+tpl->tpl[NF9_IPV4_DST_ADDR].off, tpl->tpl[NF9_IPV4_DST_ADDR].len); @@ -1201,13 +1197,17 @@ memcpy(&((struct my_iphdr *)pptrs->iph_ptr)->ip_tos, pkt+tpl->tpl[NF9_SRC_TOS].off, tpl->tpl[NF9_SRC_TOS].len); memcpy(&((struct my_tlhdr *)pptrs->tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrs->tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrs->tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrs->l4_proto = 0; memcpy(&pptrs->l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrs->class = NF_evaluate_classifiers((pptrs->f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrs->class = NF_evaluate_classifiers(entry->class, pptrs->f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, pptrs, &pptrs->bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(pptrs); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, pptrs, &pptrs->bpas, NULL); @@ -1226,8 +1226,15 @@ if (req->bpf_filter) { reset_mac(&pptrsv->v6); reset_ip6(&pptrsv->v6); - memcpy(pptrsv->v6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->v6.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); + + if (direction == DIRECTION_IN) { + memcpy(pptrsv->v6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->v6.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->v6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->v6.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + } ((struct ip6_hdr *)pptrsv->v6.iph_ptr)->ip6_ctlun.ip6_un2_vfc = 0x60; memcpy(&((struct ip6_hdr *)pptrsv->v6.iph_ptr)->ip6_src, pkt+tpl->tpl[NF9_IPV6_SRC_ADDR].off, tpl->tpl[NF9_IPV6_SRC_ADDR].len); memcpy(&((struct ip6_hdr *)pptrsv->v6.iph_ptr)->ip6_dst, pkt+tpl->tpl[NF9_IPV6_DST_ADDR].off, tpl->tpl[NF9_IPV6_DST_ADDR].len); @@ -1235,13 +1242,17 @@ /* XXX: class ID ? */ memcpy(&((struct my_tlhdr *)pptrsv->v6.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->v6.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->v6.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->v6.l4_proto = 0; memcpy(&pptrsv->v6.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->v6.class = NF_evaluate_classifiers((pptrsv->v6.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->v6.class = NF_evaluate_classifiers(entry->class, pptrsv->v6.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->v6, &pptrsv->v6.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->v6); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->v6, &pptrsv->v6.bpas, NULL); @@ -1261,9 +1272,16 @@ reset_mac_vlan(&pptrsv->vlan4); reset_ip4(&pptrsv->vlan4); - memcpy(pptrsv->vlan4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->vlan4.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); - memcpy(pptrsv->vlan4.vlan_ptr, pkt+tpl->tpl[NF9_SRC_VLAN].off, tpl->tpl[NF9_SRC_VLAN].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->vlan4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->vlan4.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + memcpy(pptrsv->vlan4.vlan_ptr, pkt+tpl->tpl[NF9_IN_VLAN].off, tpl->tpl[NF9_IN_VLAN].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->vlan4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->vlan4.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + memcpy(pptrsv->vlan4.vlan_ptr, pkt+tpl->tpl[NF9_OUT_VLAN].off, tpl->tpl[NF9_OUT_VLAN].len); + } ((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_vhl = 0x45; memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_src, pkt+tpl->tpl[NF9_IPV4_SRC_ADDR].off, tpl->tpl[NF9_IPV4_SRC_ADDR].len); memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_dst, pkt+tpl->tpl[NF9_IPV4_DST_ADDR].off, tpl->tpl[NF9_IPV4_DST_ADDR].len); @@ -1271,13 +1289,17 @@ memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_tos, pkt+tpl->tpl[NF9_SRC_TOS].off, tpl->tpl[NF9_SRC_TOS].len); memcpy(&((struct my_tlhdr *)pptrsv->vlan4.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->vlan4.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->vlan4.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->vlan4.l4_proto = 0; memcpy(&pptrsv->vlan4.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->vlan4.class = NF_evaluate_classifiers((pptrsv->vlan4.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->vlan4.class = NF_evaluate_classifiers(entry->class, pptrsv->vlan4.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->vlan4, &pptrsv->vlan4.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->vlan4); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->vlan4, &pptrsv->vlan4.bpas, NULL); @@ -1297,9 +1319,16 @@ reset_mac_vlan(&pptrsv->vlan6); reset_ip6(&pptrsv->vlan6); - memcpy(pptrsv->vlan6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->vlan6.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); - memcpy(pptrsv->vlan6.vlan_ptr, pkt+tpl->tpl[NF9_SRC_VLAN].off, tpl->tpl[NF9_SRC_VLAN].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->vlan6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->vlan6.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + memcpy(pptrsv->vlan6.vlan_ptr, pkt+tpl->tpl[NF9_IN_VLAN].off, tpl->tpl[NF9_IN_VLAN].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->vlan6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->vlan6.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + memcpy(pptrsv->vlan6.vlan_ptr, pkt+tpl->tpl[NF9_OUT_VLAN].off, tpl->tpl[NF9_OUT_VLAN].len); + } ((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_ctlun.ip6_un2_vfc = 0x60; memcpy(&((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_src, pkt+tpl->tpl[NF9_IPV6_SRC_ADDR].off, tpl->tpl[NF9_IPV6_SRC_ADDR].len); memcpy(&((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_dst, pkt+tpl->tpl[NF9_IPV6_DST_ADDR].off, tpl->tpl[NF9_IPV6_DST_ADDR].len); @@ -1307,13 +1336,17 @@ /* XXX: class ID ? */ memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->vlan6.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->vlan6.l4_proto = 0; memcpy(&pptrsv->vlan6.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->vlan6.class = NF_evaluate_classifiers((pptrsv->vlan6.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->vlan6.class = NF_evaluate_classifiers(entry->class, pptrsv->vlan6.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->vlan6, &pptrsv->vlan6.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->vlan6); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->vlan6, &pptrsv->vlan6.bpas, NULL); @@ -1335,8 +1368,14 @@ /* XXX: fix caplen */ reset_mac(&pptrsv->mpls4); - memcpy(pptrsv->mpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->mpls4.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->mpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->mpls4.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->mpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->mpls4.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + } for (idx = NF9_MPLS_LABEL_1; idx <= NF9_MPLS_LABEL_10 && tpl->tpl[idx].len; idx++, ptr += 4) { memset(ptr, 0, 4); @@ -1354,13 +1393,17 @@ memcpy(&((struct my_iphdr *)pptrsv->mpls4.iph_ptr)->ip_tos, pkt+tpl->tpl[NF9_SRC_TOS].off, tpl->tpl[NF9_SRC_TOS].len); memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->mpls4.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->mpls4.l4_proto = 0; memcpy(&pptrsv->mpls4.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->mpls4.class = NF_evaluate_classifiers((pptrsv->mpls4.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->mpls4.class = NF_evaluate_classifiers(entry->class, pptrsv->mpls4.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->mpls4, &pptrsv->mpls4.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->mpls4); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->mpls4, &pptrsv->mpls4.bpas, NULL); @@ -1382,8 +1425,14 @@ /* XXX: fix caplen */ reset_mac(&pptrsv->mpls6); - memcpy(pptrsv->mpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->mpls6.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->mpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->mpls6.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->mpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->mpls6.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + } for (idx = NF9_MPLS_LABEL_1; idx <= NF9_MPLS_LABEL_10 && tpl->tpl[idx].len; idx++, ptr += 4) { memset(ptr, 0, 4); memcpy(ptr, pkt+tpl->tpl[idx].off, tpl->tpl[idx].len); @@ -1400,13 +1449,17 @@ /* XXX: class ID ? */ memcpy(&((struct my_tlhdr *)pptrsv->mpls6.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->mpls6.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->mpls6.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->mpls6.l4_proto = 0; memcpy(&pptrsv->mpls6.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->mpls6.class = NF_evaluate_classifiers((pptrsv->mpls6.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->mpls6.class = NF_evaluate_classifiers(entry->class, pptrsv->mpls6.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->mpls6, &pptrsv->mpls6.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->mpls6); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->mpls6, &pptrsv->mpls6.bpas, NULL); @@ -1428,9 +1481,16 @@ /* XXX: fix caplen */ reset_mac_vlan(&pptrsv->vlanmpls4); - memcpy(pptrsv->vlanmpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->vlanmpls4.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); - memcpy(pptrsv->vlanmpls4.vlan_ptr, pkt+tpl->tpl[NF9_SRC_VLAN].off, tpl->tpl[NF9_SRC_VLAN].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->vlanmpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->vlanmpls4.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + memcpy(pptrsv->vlanmpls4.vlan_ptr, pkt+tpl->tpl[NF9_IN_VLAN].off, tpl->tpl[NF9_IN_VLAN].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->vlanmpls4.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->vlanmpls4.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + memcpy(pptrsv->vlanmpls4.vlan_ptr, pkt+tpl->tpl[NF9_OUT_VLAN].off, tpl->tpl[NF9_OUT_VLAN].len); + } for (idx = NF9_MPLS_LABEL_1; idx <= NF9_MPLS_LABEL_10 && tpl->tpl[idx].len; idx++, ptr += 4) { memset(ptr, 0, 4); @@ -1448,13 +1508,17 @@ memcpy(&((struct my_iphdr *)pptrsv->vlanmpls4.iph_ptr)->ip_tos, pkt+tpl->tpl[NF9_SRC_TOS].off, tpl->tpl[NF9_SRC_TOS].len); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls4.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls4.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->vlanmpls4.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->vlanmpls4.l4_proto = 0; memcpy(&pptrsv->vlanmpls4.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->vlanmpls4.class = NF_evaluate_classifiers((pptrsv->vlanmpls4.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->vlanmpls4.class = NF_evaluate_classifiers(entry->class, pptrsv->vlanmpls4.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->vlanmpls4, &pptrsv->vlanmpls4.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->vlanmpls4); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->vlanmpls4, &pptrsv->vlanmpls4.bpas, NULL); @@ -1476,9 +1540,16 @@ /* XXX: fix caplen */ reset_mac_vlan(&pptrsv->vlanmpls6); - memcpy(pptrsv->vlanmpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_SRC_MAC].off, tpl->tpl[NF9_SRC_MAC].len); - memcpy(pptrsv->vlanmpls6.mac_ptr, pkt+tpl->tpl[NF9_DST_MAC].off, tpl->tpl[NF9_DST_MAC].len); - memcpy(pptrsv->vlanmpls6.vlan_ptr, pkt+tpl->tpl[NF9_SRC_VLAN].off, tpl->tpl[NF9_SRC_VLAN].len); + if (direction == DIRECTION_IN) { + memcpy(pptrsv->vlanmpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_IN_SRC_MAC].off, tpl->tpl[NF9_IN_SRC_MAC].len); + memcpy(pptrsv->vlanmpls6.mac_ptr, pkt+tpl->tpl[NF9_IN_DST_MAC].off, tpl->tpl[NF9_IN_DST_MAC].len); + memcpy(pptrsv->vlanmpls6.vlan_ptr, pkt+tpl->tpl[NF9_IN_VLAN].off, tpl->tpl[NF9_IN_VLAN].len); + } + else if (direction == DIRECTION_OUT) { + memcpy(pptrsv->vlanmpls6.mac_ptr+ETH_ADDR_LEN, pkt+tpl->tpl[NF9_OUT_SRC_MAC].off, tpl->tpl[NF9_OUT_SRC_MAC].len); + memcpy(pptrsv->vlanmpls6.mac_ptr, pkt+tpl->tpl[NF9_OUT_DST_MAC].off, tpl->tpl[NF9_OUT_DST_MAC].len); + memcpy(pptrsv->vlanmpls6.vlan_ptr, pkt+tpl->tpl[NF9_OUT_VLAN].off, tpl->tpl[NF9_OUT_VLAN].len); + } for (idx = NF9_MPLS_LABEL_1; idx <= NF9_MPLS_LABEL_10 && tpl->tpl[idx].len; idx++, ptr += 4) { memset(ptr, 0, 4); memcpy(ptr, pkt+tpl->tpl[idx].off, tpl->tpl[idx].len); @@ -1495,13 +1566,17 @@ /* XXX: class ID ? */ memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls6.tlh_ptr)->src_port, pkt+tpl->tpl[NF9_L4_SRC_PORT].off, tpl->tpl[NF9_L4_SRC_PORT].len); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls6.tlh_ptr)->dst_port, pkt+tpl->tpl[NF9_L4_DST_PORT].off, tpl->tpl[NF9_L4_DST_PORT].len); + memcpy(&((struct my_tcphdr *)pptrsv->vlanmpls6.tlh_ptr)->th_flags, pkt+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); } /* Let's copy some relevant field */ pptrsv->vlanmpls6.l4_proto = 0; memcpy(&pptrsv->vlanmpls6.l4_proto, pkt+tpl->tpl[NF9_L4_PROTOCOL].off, tpl->tpl[NF9_L4_PROTOCOL].len); - if (config.classifiers_path && tpl->tpl[NF9_CUST_CLASS].len == 16) - pptrsv->vlanmpls6.class = NF_evaluate_classifiers((pptrsv->vlanmpls6.f_data+tpl->tpl[NF9_CUST_CLASS].off)); + if (tpl->tpl[NF9_APPLICATION_ID].len == 4) { + struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; + + if (entry) pptrsv->vlanmpls6.class = NF_evaluate_classifiers(entry->class, pptrsv->vlanmpls6.f_data+tpl->tpl[NF9_APPLICATION_ID].off); + } if (config.nfacctd_bgp_to_agent_map) NF_find_id((struct id_table *)pptrs->bta_table, &pptrsv->vlanmpls6, &pptrsv->vlanmpls6.bta, NULL); if (config.nfacctd_bgp) bgp_srcdst_lookup(&pptrsv->vlanmpls6); if (config.nfacctd_bgp_peer_as_src_map) NF_find_id((struct id_table *)pptrs->bpas_table, &pptrsv->vlanmpls6, &pptrsv->vlanmpls6.bpas, NULL); @@ -1538,6 +1613,58 @@ if (off < len) goto process_flowset; } +void process_raw_packet(unsigned char *pkt, u_int16_t len, struct packet_ptrs_vector *pptrsv, + struct plugin_requests *req) +{ + struct packet_ptrs *pptrs = &pptrsv->v4; + u_int16_t nfv; + + /* basic length check against longest NetFlow header */ + if (len < NfHdrV8Sz) { + notify_malf_packet(LOG_INFO, "INFO: discarding short NetFlow packet", (struct sockaddr *) pptrs->f_agent); + xflow_tot_bad_datagrams++; + return; + } + + nfv = ntohs(((struct struct_header_v5 *)pkt)->version); + + if (nfv != 1 && nfv != 5 && nfv != 7 && nfv != 8 && nfv != 9) { + notify_malf_packet(LOG_INFO, "INFO: discarding unknown NetFlow packet", (struct sockaddr *) pptrs->f_agent); + xflow_tot_bad_datagrams++; + return; + } + + pptrs->f_header = pkt; + + switch (nfv) { + case 5: + case 7: + case 8: + pptrs->seqno = ntohl(((struct struct_header_v5 *)pkt)->flow_sequence); + break; + case 9: + pptrs->seqno = ntohl(((struct struct_header_v9 *)pkt)->flow_sequence); + break; + default: + pptrs->seqno = 0; + break; + } + + if (config.debug) { + struct host_addr a; + u_char agent_addr[50]; + u_int16_t agent_port; + + sa_to_addr((struct sockaddr *)pptrs->f_agent, &a, &agent_port); + addr_to_str(agent_addr, &a); + + Log(LOG_DEBUG, "DEBUG ( default/core ): Received NetFlow packet from [%s:%u] version [%u] seqno [%u]\n", agent_addr, agent_port, nfv, pptrsv->v4.seqno); + } + + if (config.pre_tag_map) NF_find_id((struct id_table *)pptrs->idtable, pptrs, &pptrs->tag, &pptrs->tag2); + exec_plugins(pptrs); +} + void compute_once() { struct pkt_data dummy; @@ -1545,6 +1672,7 @@ CounterSz = sizeof(dummy.pkt_len); PdataSz = sizeof(struct pkt_data); PpayloadSz = sizeof(struct pkt_payload); + PmsgSz = sizeof(struct pkt_msg); PextrasSz = sizeof(struct pkt_extras); PbgpSz = sizeof(struct pkt_bgp_primitives); ChBufHdrSz = sizeof(struct ch_buf_hdr); @@ -1565,6 +1693,7 @@ PptrsSz = sizeof(struct packet_ptrs); CSSz = sizeof(struct class_st); HostAddrSz = sizeof(struct host_addr); + UDPHdrSz = sizeof(struct my_udphdr); #if defined ENABLE_IPV6 IP6HdrSz = sizeof(struct ip6_hdr); @@ -1575,12 +1704,26 @@ u_int16_t NF_evaluate_flow_type(struct template_cache_entry *tpl, struct packet_ptrs *pptrs) { - u_int8_t ret=0; + u_int16_t ret=0; - if (tpl->tpl[NF9_SRC_VLAN].len && *(pptrs->f_data+tpl->tpl[NF9_SRC_VLAN].off) > 0) ret += NF9_FTYPE_VLAN; + if ((tpl->tpl[NF9_IN_VLAN].len && *(pptrs->f_data+tpl->tpl[NF9_IN_VLAN].off) > 0) || + (tpl->tpl[NF9_OUT_VLAN].len && *(pptrs->f_data+tpl->tpl[NF9_OUT_VLAN].off) > 0)) ret += NF9_FTYPE_VLAN; if (tpl->tpl[NF9_MPLS_LABEL_1].len /* check: value > 0 ? */) ret += NF9_FTYPE_MPLS; - if (*(pptrs->f_data+tpl->tpl[NF9_IP_PROTOCOL_VERSION].off) == 4 || tpl->tpl[NF9_IPV4_SRC_ADDR].len > 0); - else if (*(pptrs->f_data+tpl->tpl[NF9_IP_PROTOCOL_VERSION].off) == 6 || tpl->tpl[NF9_IPV6_SRC_ADDR].len > 0) ret += NF9_FTYPE_IPV6; + + /* Explicit IP protocol definition first; a bit of heuristics as fallback */ + if (*(pptrs->f_data+tpl->tpl[NF9_IP_PROTOCOL_VERSION].off) == 4); + else if (*(pptrs->f_data+tpl->tpl[NF9_IP_PROTOCOL_VERSION].off) == 6) ret += NF9_FTYPE_IPV6; + else if (tpl->tpl[NF9_IPV4_SRC_ADDR].len > 0); + else if (tpl->tpl[NF9_IPV6_SRC_ADDR].len > 0) ret += NF9_FTYPE_IPV6; + + return ret; +} + +u_int16_t NF_evaluate_direction(struct template_cache_entry *tpl, struct packet_ptrs *pptrs) +{ + u_int16_t ret = DIRECTION_IN; + + if (tpl->tpl[NF9_DIRECTION].len && *(pptrs->f_data+tpl->tpl[NF9_DIRECTION].off) == 1) ret = DIRECTION_OUT; return ret; } diff -Nru pmacct-0.12.1/src/nfacctd.h pmacct-0.12.5/src/nfacctd.h --- pmacct-0.12.1/src/nfacctd.h 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/nfacctd.h 2010-11-03 21:29:26.000000000 +0000 @@ -1,533 +1,682 @@ -/* Netflow stuff */ + /* Netflow stuff */ -/* NetFlow Export Version 1 Header Format */ -struct struct_header_v1 { - u_int16_t version; /* Current version = 1 */ - u_int16_t count; /* The number of records in PDU. */ - u_int32_t SysUptime; /* Current time in msecs since router booted */ - u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ - u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ -}; - -/* NetFlow Export Version 5 Header Format */ -struct struct_header_v5 { - u_int16_t version; /* Version = 5 */ - u_int16_t count; /* The number of records in PDU. */ - u_int32_t SysUptime; /* Current time in msecs since router booted */ - u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ - u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ - u_int32_t flow_sequence; /* Sequence number of total flows seen */ - unsigned char engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ - unsigned char engine_id; /* Slot number of the flow switching engine */ - u_int16_t sampling; -}; - -/* NetFlow Export Version 7 Header Format */ -struct struct_header_v7 { - u_int16_t version; /* Version = 7 */ - u_int16_t count; /* The number of records in the PDU */ - u_int32_t SysUptime; /* Current time in millisecs since router booted */ - u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ - u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ - u_int32_t flow_sequence; /* Seq counter of total flows seen */ - u_int8_t engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ - u_int8_t engine_id; /* Slot number of the flow switching engine */ - u_int16_t reserved; -}; - -/* NetFlow Export Version 8 Header Format */ -struct struct_header_v8 { - u_int16_t version; /* Version = 8 */ - u_int16_t count; /* The number of records in the PDU */ - u_int32_t SysUptime; /* Current time in millisecs since router booted */ - u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ - u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ - u_int32_t flow_sequence; /* Seq counter of total flows seen */ - unsigned char engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ - unsigned char engine_id; /* Slot number of the flow switching engine */ - u_int8_t aggregation; /* Aggregation method being used */ - u_int8_t agg_version; /* Version of the aggregation export */ - u_int32_t reserved; -}; - -/* NetFlow Export Version 9 Header Format */ -struct struct_header_v9 { - u_int16_t version; /* version = 9 */ - u_int16_t count; /* The number of records in PDU. */ - u_int32_t SysUptime; /* Current time in msecs since router booted */ - u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ - u_int32_t flow_sequence; /* Sequence number of total flows seen */ - u_int32_t source_id; /* Source id */ -}; - -/* NetFlow Export version 1 */ -struct struct_export_v1 { - struct in_addr srcaddr; /* Source IP Address */ - struct in_addr dstaddr; /* Destination IP Address */ - struct in_addr nexthop; /* Next hop router's IP Address */ - u_int16_t input; /* Input interface index */ - u_int16_t output; /* Output interface index */ - u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st & last packet in this flow)*/ - u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st & last packet in this flow)*/ - u_int32_t First; /* SysUptime at start of flow */ - u_int32_t Last; /* and of last packet of the flow */ - u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ - u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ - u_int16_t pad; /* pad to word boundary */ - unsigned char prot; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ - unsigned char tos; /* IP Type-of-Service */ - unsigned char pad_2[8]; /* pad to word boundary */ -}; - -/* NetFlow Export version 5 */ -struct struct_export_v5 { - struct in_addr srcaddr; /* Source IP Address */ - struct in_addr dstaddr; /* Destination IP Address */ - struct in_addr nexthop; /* Next hop router's IP Address */ - u_int16_t input; /* Input interface index */ - u_int16_t output; /* Output interface index */ - u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st & last packet in this flow) */ - u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st & last packet in this flow) */ - u_int32_t First; /* SysUptime at start of flow */ - u_int32_t Last; /* and of last packet of the flow */ - u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ - u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ - unsigned char pad; /* pad to word boundary */ - unsigned char tcp_flags; /* Cumulative OR of tcp flags */ - unsigned char prot; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ - unsigned char tos; /* IP Type-of-Service */ - u_int16_t src_as; /* source peer/origin Autonomous System */ - u_int16_t dst_as; /* dst peer/origin Autonomous System */ - unsigned char src_mask; /* source route's mask bits */ - unsigned char dst_mask; /* destination route's mask bits */ - u_int16_t pad_1; /* pad to word boundary */ -}; - -/* NetFlow Export version 7 */ -struct struct_export_v7 { - u_int32_t srcaddr; /* Source IP Address */ - u_int32_t dstaddr; /* Destination IP Address */ - u_int32_t nexthop; /* Next hop router's IP Address */ - u_int16_t input; /* Input interface index */ - u_int16_t output; /* Output interface index */ - u_int32_t dPkts; /* Packets sent in Duration */ - u_int32_t dOctets; /* Octets sent in Duration. */ - u_int32_t First; /* SysUptime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t srcport; /* TCP/UDP source port number or equivalent */ - u_int16_t dstport; /* TCP/UDP destination port number or equiv */ - u_int8_t pad; - u_int8_t tcp_flags; /* Cumulative OR of tcp flags */ - u_int8_t prot; /* IP protocol, e.g., 6=TCP, 17=UDP, ... */ - u_int8_t tos; /* IP Type-of-Service */ - u_int16_t src_as; /* originating AS of source address */ - u_int16_t dst_as; /* originating AS of destination address */ - u_int8_t src_mask; /* source address prefix mask bits */ - u_int8_t dst_mask; /* destination address prefix mask bits */ - u_int16_t drops; - u_int32_t router_sc; /* Router which is shortcut by switch */ -}; - -struct struct_export_v8_1 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t src_as; /* originating AS of source address */ - u_int16_t dst_as; /* originating AS of destination address */ - u_int16_t input; /* input interface index */ - u_int16_t output; /* output interface index */ -}; - -struct struct_export_v8_2 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int8_t prot; /* IP protocol */ - u_int8_t pad; - u_int16_t reserved; - u_int16_t srcport; /* TCP/UDP source port number of equivalent */ - u_int16_t dstport; /* TCP/UDP dst port number of equivalent */ -}; - -struct struct_export_v8_3 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t src_prefix; - u_int8_t src_mask; - u_int8_t pad; - u_int16_t src_as; - u_int16_t input; - u_int16_t reserved; -}; - -struct struct_export_v8_4 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t dst_prefix; - u_int8_t dst_mask; - u_int8_t pad; - u_int16_t dst_as; - u_int16_t output; - u_int16_t reserved; -}; - -struct struct_export_v8_5 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t src_prefix; - u_int32_t dst_prefix; - u_int8_t dst_mask; - u_int8_t src_mask; - u_int16_t reserved; - u_int16_t src_as; - u_int16_t dst_as; - u_int16_t input; - u_int16_t output; -}; - -struct struct_export_v8_6 { - u_int32_t dstaddr; /* destination IP address */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t output; /* output interface index */ - u_int8_t tos; /* tos */ - u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ - u_int32_t extra_pkts; /* packets that exceed the contract */ - u_int32_t router_sc; /* IP address of the router being shortcut */ -}; - -struct struct_export_v8_7 { - u_int32_t dstaddr; /* destination IP address */ - u_int32_t srcaddr; /* source address */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t output; /* output interface index */ - u_int16_t input; /* input interface index */ - u_int8_t tos; /* tos */ - u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ - u_int16_t reserved; - u_int32_t extra_pkts; /* packets that exceed the contract */ - u_int32_t router_sc; /* IP address of the router being shortcut */ -}; - -struct struct_export_v8_8 { - u_int32_t dstaddr; /* destination IP address */ - u_int32_t srcaddr; /* source IP address */ - u_int16_t dstport; /* TCP/UDP destination port */ - u_int16_t srcport; /* TCP/UDP source port */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t output; /* output interface index */ - u_int16_t input; /* input interface index */ - u_int8_t tos; /* tos */ - u_int8_t prot; /* protocol */ - u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ - u_int8_t reserved; - u_int32_t extra_pkts; /* packets that exceed the contract */ - u_int32_t router_sc; /* IP address of the router being shortcut */ -}; - -struct struct_export_v8_9 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int16_t src_as; /* originating AS of source address */ - u_int16_t dst_as; /* originating AS of destination address */ - u_int16_t input; /* input interface index */ - u_int16_t output; /* output interface index */ - u_int8_t tos; /* tos */ - u_int8_t pad; - u_int16_t reserved; -}; - -struct struct_export_v8_10 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int8_t prot; /* IP protocol */ - u_int8_t tos; /* tos */ - u_int16_t reserved; - u_int16_t srcport; /* TCP/UDP source port number of equivalent */ - u_int16_t dstport; /* TCP/UDP dst port number of equivalent */ - u_int16_t input; /* input interface */ - u_int16_t output; /* output interface index */ -}; - -struct struct_export_v8_11 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t src_prefix; /* Source Prefix */ - u_int8_t src_mask; /* Source Prefix mask length */ - u_int8_t tos; /* tos */ - u_int16_t src_as; /* Source AS */ - u_int16_t input; /* input interface */ - u_int16_t reserved; -}; - -struct struct_export_v8_12 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t dst_prefix; /* Destination Prefix */ - u_int8_t dst_mask; /* Destination Prefix mask length */ - u_int8_t tos; /* tos */ - u_int16_t dst_as; /* Destination AS */ - u_int16_t output; /* output interface */ - u_int16_t reserved; -}; - -struct struct_export_v8_13 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t src_prefix; /* Source Prefix */ - u_int32_t dst_prefix; /* Destination Prefix */ - u_int8_t dst_mask; /* Destination Prefix mask length */ - u_int8_t src_mask; /* Source Prefix mask length */ - u_int8_t tos; /* tos */ - u_int8_t pad; - u_int16_t src_as; /* Source AS */ - u_int16_t dst_as; /* Destination AS */ - u_int16_t input; /* input interface */ - u_int16_t output; /* output interface */ -}; - -struct struct_export_v8_14 { - u_int32_t dFlows; /* Number of flows */ - u_int32_t dPkts; /* Packets sent in duration */ - u_int32_t dOctets; /* Octets sent in duration */ - u_int32_t First; /* SysUpTime at start of flow */ - u_int32_t Last; /* and of last packet of flow */ - u_int32_t src_prefix; /* Source Prefix */ - u_int32_t dst_prefix; /* Destination Prefix */ - u_int8_t dst_mask; /* Destination Prefix mask length */ - u_int8_t src_mask; /* Source Prefix mask length */ - u_int8_t tos; /* tos */ - u_int8_t prot; /* protocol */ - u_int16_t srcport; /* Source port */ - u_int16_t dstport; /* Destination port */ - u_int16_t input; /* input interface */ - u_int16_t output; /* output interface */ -}; - -/* NetFlow Export version 9 */ -struct template_field_v9 { - u_int16_t type; - u_int16_t len; -}; - -struct template_hdr_v9 { - u_int16_t template_id; - u_int16_t num; -}; - -struct options_template_hdr_v9 { - u_int16_t template_id; - u_int16_t scope_len; - u_int16_t option_len; -}; - -struct data_hdr_v9 { - u_int16_t flow_id; /* == 0: template; == 1: options template; >= 256: data */ - u_int16_t flow_len; -}; - -/* defines */ -#define DEFAULT_NFACCTD_PORT 2100 -#define NETFLOW_MSG_SIZE 1550 -#define V1_MAXFLOWS 24 /* max records in V1 packet */ -#define V5_MAXFLOWS 30 /* max records in V5 packet */ -#define V7_MAXFLOWS 27 /* max records in V7 packet */ -#define V8_1_MAXFLOWS 51 /* max records in V8 AS packet */ -#define V8_2_MAXFLOWS 51 /* max records in V8 PROTO PORT packet */ -#define V8_3_MAXFLOWS 44 /* max records in V8 SRC PREFIX packet */ -#define V8_4_MAXFLOWS 44 /* max records in V8 DST PREFIX packet */ -#define V8_5_MAXFLOWS 35 /* max records in V8 PREFIX packet */ -#define V8_6_MAXFLOWS 44 /* max records in V8 DESTONLY packet */ -#define V8_7_MAXFLOWS 35 /* max records in V8 SRC_DEST packet */ -#define V8_8_MAXFLOWS 32 /* max records in V8 FULL_FLOW packet */ -#define V8_9_MAXFLOWS 44 /* max records in V8 AS_TOS packet */ -#define V8_10_MAXFLOWS 44 /* max records in V8 PROT_PORT_TOS packet */ -#define V8_11_MAXFLOWS 44 /* max records in V8 SRC_PREFIX_TOS packet */ -#define V8_12_MAXFLOWS 44 /* max records in V8 DST_PREFIX_TOS packet */ -#define V8_13_MAXFLOWS 35 /* max records in V8 PREFIX_TOS packet */ -#define V8_14_MAXFLOWS 35 /* max records in V8 PREFIX_PORT_TOS packet */ -#define TEMPLATE_CACHE_ENTRIES 255 - -#define NF_TIME_MSECS 0 /* times are in msecs */ -#define NF_TIME_SECS 1 /* times are in secs */ -#define NF_TIME_NEW 2 /* ignore netflow engine times and generate new ones */ - -#define NF_AS_KEEP 0 /* Keep AS numbers in NetFlow packets */ -#define NF_AS_NEW 1 /* ignore ASN from NetFlow and generate from network files */ -#define NF_AS_BGP 2 /* ignore ASN from NetFlow and generate from BGP peerings */ - -#define NF_NET_COMPAT 0x00000000 /* Backward compatibility selection */ -#define NF_NET_KEEP 0x00000001 /* Determine IP network prefixes from NetFlow data */ -#define NF_NET_NEW 0x00000002 /* Determine IP network prefixes from network files */ -#define NF_NET_BGP 0x00000004 /* Determine IP network prefixes from BGP peerings */ -#define NF_NET_STATIC 0x00000008 /* Determine IP network prefixes from static mask */ - -/* NetFlow V9 stuff */ -#define NF9_TEMPLATE_FLOWSET_ID 0 -#define NF9_OPTIONS_FLOWSET_ID 1 -#define NF9_MIN_RECORD_FLOWSET_ID 256 -#define NF9_MAX_DEFINED_FIELD 210 - -/* Flowset record types the we care about */ -#define NF9_IN_BYTES 1 -#define NF9_IN_PACKETS 2 -#define NF9_FLOWS 3 -#define NF9_L4_PROTOCOL 4 -#define NF9_SRC_TOS 5 -#define NF9_TCP_FLAGS 6 -#define NF9_L4_SRC_PORT 7 -#define NF9_IPV4_SRC_ADDR 8 -#define NF9_SRC_MASK 9 -#define NF9_INPUT_SNMP 10 -#define NF9_L4_DST_PORT 11 -#define NF9_IPV4_DST_ADDR 12 -#define NF9_DST_MASK 13 -#define NF9_OUTPUT_SNMP 14 -#define NF9_IPV4_NEXT_HOP 15 -#define NF9_SRC_AS 16 -#define NF9_DST_AS 17 -#define NF9_BGP_IPV4_NEXT_HOP 18 -#define NF9_MUL_DST_PKTS 19 -#define NF9_MUL_DST_BYTES 20 -/* ... */ -#define NF9_LAST_SWITCHED 21 -#define NF9_FIRST_SWITCHED 22 -/* ... */ -#define NF9_IPV6_SRC_ADDR 27 -#define NF9_IPV6_DST_ADDR 28 -#define NF9_IPV6_SRC_MASK 29 -#define NF9_IPV6_DST_MASK 30 -#define NF9_ICMP_TYPE 32 -/* ... */ -#define NF9_ENGINE_TYPE 38 -#define NF9_ENGINE_ID 39 -/* ... */ -#define NF9_SRC_MAC 56 -#define NF9_DST_MAC 57 -#define NF9_SRC_VLAN 58 -#define NF9_DST_VLAN 59 -#define NF9_IP_PROTOCOL_VERSION 60 -#define NF9_DIRECTION 61 -#define NF9_IPV6_NEXT_HOP 62 -#define NF9_BGP_IPV6_NEXT_HOP 63 -/* ... */ -#define NF9_MPLS_LABEL_1 70 -#define NF9_MPLS_LABEL_2 71 -#define NF9_MPLS_LABEL_3 72 -#define NF9_MPLS_LABEL_4 73 -#define NF9_MPLS_LABEL_5 74 -#define NF9_MPLS_LABEL_6 75 -#define NF9_MPLS_LABEL_7 76 -#define NF9_MPLS_LABEL_8 77 -#define NF9_MPLS_LABEL_9 78 -#define NF9_MPLS_LABEL_10 79 -/* ... */ -#define NF9_CUST_CLASS 200 -#define NF9_CUST_TAG 201 -#define NF9_CUST_TAG2 202 - -#define NF9_FTYPE_IPV4 0 -#define NF9_FTYPE_IPV6 1 -#define NF9_FTYPE_VLAN 5 -#define NF9_FTYPE_VLAN_IPV4 5 -#define NF9_FTYPE_VLAN_IPV6 6 -#define NF9_FTYPE_MPLS 10 -#define NF9_FTYPE_MPLS_IPV4 10 -#define NF9_FTYPE_MPLS_IPV6 11 -#define NF9_FTYPE_VLAN_MPLS 15 -#define NF9_FTYPE_VLAN_MPLS_IPV4 15 -#define NF9_FTYPE_VLAN_MPLS_IPV6 16 - -/* Sampling */ -#define NF9_SAMPLING_INTERVAL 34 -#define NF9_SAMPLING_ALGORITHM 35 -#define NF9_FLOW_SAMPLER_ID 48 -#define NF9_FLOW_SAMPLER_MODE 49 -#define NF9_FLOW_SAMPLER_INTERVAL 50 - -#define NF9_OPT_SCOPE_SYSTEM 1 -#define NF9_OPT_SCOPE_IF 2 -#define NF9_OPT_SCOPE_LC 3 -#define NF9_OPT_SCOPE_CACHE 4 -#define NF9_OPT_SCOPE_TPL 5 - -/* Ordered Template field */ -struct otpl_field { - u_int16_t off; - u_int16_t len; -}; - -struct template_cache_entry { - struct host_addr agent; /* NetFlow Exporter agent */ - u_int32_t source_id; /* Exporter Observation Domain */ - u_int16_t template_id; /* template ID */ - u_int16_t template_type; /* Data = 0, Options = 1 */ - u_int16_t num; /* number of fields described into template */ - u_int16_t len; /* total length of the described flowset */ - struct otpl_field tpl[NF9_MAX_DEFINED_FIELD]; - struct template_cache_entry *next; -}; - -struct template_cache { - u_int16_t num; - struct template_cache_entry *c[TEMPLATE_CACHE_ENTRIES]; -}; - -typedef void (*v8_filter_handler)(struct packet_ptrs *, void *); -struct v8_handler_entry { - u_int8_t max_flows; - u_int8_t exp_size; - v8_filter_handler fh; -}; - -/* functions */ -#if (!defined __NFACCTD_C) -#define EXT extern -#else -#define EXT -#endif -EXT void process_v1_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); -EXT void process_v5_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); -EXT void process_v7_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); -EXT void process_v8_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); -EXT void process_v9_packet(unsigned char *, u_int16_t, struct packet_ptrs_vector *, struct plugin_requests *); -EXT u_int16_t NF_evaluate_flow_type(struct template_cache_entry *, struct packet_ptrs *); + /* NetFlow Export Version 1 Header Format */ + struct struct_header_v1 { + u_int16_t version; /* Current version = 1 */ + u_int16_t count; /* The number of records in PDU. */ + u_int32_t SysUptime; /* Current time in msecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ + }; + + /* NetFlow Export Version 5 Header Format */ + struct struct_header_v5 { + u_int16_t version; /* Version = 5 */ + u_int16_t count; /* The number of records in PDU. */ + u_int32_t SysUptime; /* Current time in msecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ + u_int32_t flow_sequence; /* Sequence number of total flows seen */ + unsigned char engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ + unsigned char engine_id; /* Slot number of the flow switching engine */ + u_int16_t sampling; + }; + + /* NetFlow Export Version 7 Header Format */ + struct struct_header_v7 { + u_int16_t version; /* Version = 7 */ + u_int16_t count; /* The number of records in the PDU */ + u_int32_t SysUptime; /* Current time in millisecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ + u_int32_t flow_sequence; /* Seq counter of total flows seen */ + u_int8_t engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ + u_int8_t engine_id; /* Slot number of the flow switching engine */ + u_int16_t reserved; + }; + + /* NetFlow Export Version 8 Header Format */ + struct struct_header_v8 { + u_int16_t version; /* Version = 8 */ + u_int16_t count; /* The number of records in the PDU */ + u_int32_t SysUptime; /* Current time in millisecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t unix_nsecs; /* Residual nanoseconds since 0000 UTC 1970 */ + u_int32_t flow_sequence; /* Seq counter of total flows seen */ + unsigned char engine_type; /* Type of flow switching engine (RP,VIP,etc.) */ + unsigned char engine_id; /* Slot number of the flow switching engine */ + u_int8_t aggregation; /* Aggregation method being used */ + u_int8_t agg_version; /* Version of the aggregation export */ + u_int32_t reserved; + }; + + /* NetFlow Export Version 9 Header Format */ + struct struct_header_v9 { + u_int16_t version; /* version = 9 */ + u_int16_t count; /* The number of records in PDU. */ + u_int32_t SysUptime; /* Current time in msecs since router booted */ + u_int32_t unix_secs; /* Current seconds since 0000 UTC 1970 */ + u_int32_t flow_sequence; /* Sequence number of total flows seen */ + u_int32_t source_id; /* Source id */ + }; + + /* NetFlow Export version 1 */ + struct struct_export_v1 { + struct in_addr srcaddr; /* Source IP Address */ + struct in_addr dstaddr; /* Destination IP Address */ + struct in_addr nexthop; /* Next hop router's IP Address */ + u_int16_t input; /* Input interface index */ + u_int16_t output; /* Output interface index */ + u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st & last packet in this flow)*/ + u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st & last packet in this flow)*/ + u_int32_t First; /* SysUptime at start of flow */ + u_int32_t Last; /* and of last packet of the flow */ + u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ + u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ + u_int16_t pad; /* pad to word boundary */ + unsigned char prot; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ + unsigned char tos; /* IP Type-of-Service */ + unsigned char pad_2[8]; /* pad to word boundary */ + }; + + /* NetFlow Export version 5 */ + struct struct_export_v5 { + struct in_addr srcaddr; /* Source IP Address */ + struct in_addr dstaddr; /* Destination IP Address */ + struct in_addr nexthop; /* Next hop router's IP Address */ + u_int16_t input; /* Input interface index */ + u_int16_t output; /* Output interface index */ + u_int32_t dPkts; /* Packets sent in Duration (milliseconds between 1st & last packet in this flow) */ + u_int32_t dOctets; /* Octets sent in Duration (milliseconds between 1st & last packet in this flow) */ + u_int32_t First; /* SysUptime at start of flow */ + u_int32_t Last; /* and of last packet of the flow */ + u_int16_t srcport; /* TCP/UDP source port number (.e.g, FTP, Telnet, etc.,or equivalent) */ + u_int16_t dstport; /* TCP/UDP destination port number (.e.g, FTP, Telnet, etc.,or equivalent) */ + unsigned char pad; /* pad to word boundary */ + unsigned char tcp_flags; /* Cumulative OR of tcp flags */ + unsigned char prot; /* IP protocol, e.g., 6=TCP, 17=UDP, etc... */ + unsigned char tos; /* IP Type-of-Service */ + u_int16_t src_as; /* source peer/origin Autonomous System */ + u_int16_t dst_as; /* dst peer/origin Autonomous System */ + unsigned char src_mask; /* source route's mask bits */ + unsigned char dst_mask; /* destination route's mask bits */ + u_int16_t pad_1; /* pad to word boundary */ + }; + + /* NetFlow Export version 7 */ + struct struct_export_v7 { + u_int32_t srcaddr; /* Source IP Address */ + u_int32_t dstaddr; /* Destination IP Address */ + u_int32_t nexthop; /* Next hop router's IP Address */ + u_int16_t input; /* Input interface index */ + u_int16_t output; /* Output interface index */ + u_int32_t dPkts; /* Packets sent in Duration */ + u_int32_t dOctets; /* Octets sent in Duration. */ + u_int32_t First; /* SysUptime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t srcport; /* TCP/UDP source port number or equivalent */ + u_int16_t dstport; /* TCP/UDP destination port number or equiv */ + u_int8_t pad; + u_int8_t tcp_flags; /* Cumulative OR of tcp flags */ + u_int8_t prot; /* IP protocol, e.g., 6=TCP, 17=UDP, ... */ + u_int8_t tos; /* IP Type-of-Service */ + u_int16_t src_as; /* originating AS of source address */ + u_int16_t dst_as; /* originating AS of destination address */ + u_int8_t src_mask; /* source address prefix mask bits */ + u_int8_t dst_mask; /* destination address prefix mask bits */ + u_int16_t drops; + u_int32_t router_sc; /* Router which is shortcut by switch */ + }; + + struct struct_export_v8_1 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t src_as; /* originating AS of source address */ + u_int16_t dst_as; /* originating AS of destination address */ + u_int16_t input; /* input interface index */ + u_int16_t output; /* output interface index */ + }; + + struct struct_export_v8_2 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int8_t prot; /* IP protocol */ + u_int8_t pad; + u_int16_t reserved; + u_int16_t srcport; /* TCP/UDP source port number of equivalent */ + u_int16_t dstport; /* TCP/UDP dst port number of equivalent */ + }; + + struct struct_export_v8_3 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t src_prefix; + u_int8_t src_mask; + u_int8_t pad; + u_int16_t src_as; + u_int16_t input; + u_int16_t reserved; + }; + + struct struct_export_v8_4 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t dst_prefix; + u_int8_t dst_mask; + u_int8_t pad; + u_int16_t dst_as; + u_int16_t output; + u_int16_t reserved; + }; + + struct struct_export_v8_5 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t src_prefix; + u_int32_t dst_prefix; + u_int8_t dst_mask; + u_int8_t src_mask; + u_int16_t reserved; + u_int16_t src_as; + u_int16_t dst_as; + u_int16_t input; + u_int16_t output; + }; + + struct struct_export_v8_6 { + u_int32_t dstaddr; /* destination IP address */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t output; /* output interface index */ + u_int8_t tos; /* tos */ + u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ + u_int32_t extra_pkts; /* packets that exceed the contract */ + u_int32_t router_sc; /* IP address of the router being shortcut */ + }; + + struct struct_export_v8_7 { + u_int32_t dstaddr; /* destination IP address */ + u_int32_t srcaddr; /* source address */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t output; /* output interface index */ + u_int16_t input; /* input interface index */ + u_int8_t tos; /* tos */ + u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ + u_int16_t reserved; + u_int32_t extra_pkts; /* packets that exceed the contract */ + u_int32_t router_sc; /* IP address of the router being shortcut */ + }; + + struct struct_export_v8_8 { + u_int32_t dstaddr; /* destination IP address */ + u_int32_t srcaddr; /* source IP address */ + u_int16_t dstport; /* TCP/UDP destination port */ + u_int16_t srcport; /* TCP/UDP source port */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t output; /* output interface index */ + u_int16_t input; /* input interface index */ + u_int8_t tos; /* tos */ + u_int8_t prot; /* protocol */ + u_int8_t marked_tos; /* tos of pkts that exceeded the contract */ + u_int8_t reserved; + u_int32_t extra_pkts; /* packets that exceed the contract */ + u_int32_t router_sc; /* IP address of the router being shortcut */ + }; + + struct struct_export_v8_9 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int16_t src_as; /* originating AS of source address */ + u_int16_t dst_as; /* originating AS of destination address */ + u_int16_t input; /* input interface index */ + u_int16_t output; /* output interface index */ + u_int8_t tos; /* tos */ + u_int8_t pad; + u_int16_t reserved; + }; + + struct struct_export_v8_10 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int8_t prot; /* IP protocol */ + u_int8_t tos; /* tos */ + u_int16_t reserved; + u_int16_t srcport; /* TCP/UDP source port number of equivalent */ + u_int16_t dstport; /* TCP/UDP dst port number of equivalent */ + u_int16_t input; /* input interface */ + u_int16_t output; /* output interface index */ + }; + + struct struct_export_v8_11 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t src_prefix; /* Source Prefix */ + u_int8_t src_mask; /* Source Prefix mask length */ + u_int8_t tos; /* tos */ + u_int16_t src_as; /* Source AS */ + u_int16_t input; /* input interface */ + u_int16_t reserved; + }; + + struct struct_export_v8_12 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t dst_prefix; /* Destination Prefix */ + u_int8_t dst_mask; /* Destination Prefix mask length */ + u_int8_t tos; /* tos */ + u_int16_t dst_as; /* Destination AS */ + u_int16_t output; /* output interface */ + u_int16_t reserved; + }; + + struct struct_export_v8_13 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t src_prefix; /* Source Prefix */ + u_int32_t dst_prefix; /* Destination Prefix */ + u_int8_t dst_mask; /* Destination Prefix mask length */ + u_int8_t src_mask; /* Source Prefix mask length */ + u_int8_t tos; /* tos */ + u_int8_t pad; + u_int16_t src_as; /* Source AS */ + u_int16_t dst_as; /* Destination AS */ + u_int16_t input; /* input interface */ + u_int16_t output; /* output interface */ + }; + + struct struct_export_v8_14 { + u_int32_t dFlows; /* Number of flows */ + u_int32_t dPkts; /* Packets sent in duration */ + u_int32_t dOctets; /* Octets sent in duration */ + u_int32_t First; /* SysUpTime at start of flow */ + u_int32_t Last; /* and of last packet of flow */ + u_int32_t src_prefix; /* Source Prefix */ + u_int32_t dst_prefix; /* Destination Prefix */ + u_int8_t dst_mask; /* Destination Prefix mask length */ + u_int8_t src_mask; /* Source Prefix mask length */ + u_int8_t tos; /* tos */ + u_int8_t prot; /* protocol */ + u_int16_t srcport; /* Source port */ + u_int16_t dstport; /* Destination port */ + u_int16_t input; /* input interface */ + u_int16_t output; /* output interface */ + }; + + /* NetFlow Export version 9 */ + struct template_field_v9 { + u_int16_t type; + u_int16_t len; + }; + + struct template_hdr_v9 { + u_int16_t template_id; + u_int16_t num; + }; + + struct options_template_hdr_v9 { + u_int16_t template_id; + u_int16_t scope_len; + u_int16_t option_len; + }; + + struct data_hdr_v9 { + u_int16_t flow_id; /* == 0: template; == 1: options template; >= 256: data */ + u_int16_t flow_len; + }; + + /* defines */ + #define DEFAULT_NFACCTD_PORT 2100 + #define NETFLOW_MSG_SIZE 1550 + #define V1_MAXFLOWS 24 /* max records in V1 packet */ + #define V5_MAXFLOWS 30 /* max records in V5 packet */ + #define V7_MAXFLOWS 27 /* max records in V7 packet */ + #define V8_1_MAXFLOWS 51 /* max records in V8 AS packet */ + #define V8_2_MAXFLOWS 51 /* max records in V8 PROTO PORT packet */ + #define V8_3_MAXFLOWS 44 /* max records in V8 SRC PREFIX packet */ + #define V8_4_MAXFLOWS 44 /* max records in V8 DST PREFIX packet */ + #define V8_5_MAXFLOWS 35 /* max records in V8 PREFIX packet */ + #define V8_6_MAXFLOWS 44 /* max records in V8 DESTONLY packet */ + #define V8_7_MAXFLOWS 35 /* max records in V8 SRC_DEST packet */ + #define V8_8_MAXFLOWS 32 /* max records in V8 FULL_FLOW packet */ + #define V8_9_MAXFLOWS 44 /* max records in V8 AS_TOS packet */ + #define V8_10_MAXFLOWS 44 /* max records in V8 PROT_PORT_TOS packet */ + #define V8_11_MAXFLOWS 44 /* max records in V8 SRC_PREFIX_TOS packet */ + #define V8_12_MAXFLOWS 44 /* max records in V8 DST_PREFIX_TOS packet */ + #define V8_13_MAXFLOWS 35 /* max records in V8 PREFIX_TOS packet */ + #define V8_14_MAXFLOWS 35 /* max records in V8 PREFIX_PORT_TOS packet */ + #define TEMPLATE_CACHE_ENTRIES 255 + + #define NF_TIME_MSECS 0 /* times are in msecs */ + #define NF_TIME_SECS 1 /* times are in secs */ + #define NF_TIME_NEW 2 /* ignore netflow engine times and generate new ones */ + + #define NF_AS_KEEP 0 /* Keep AS numbers in NetFlow packets */ + #define NF_AS_NEW 1 /* ignore ASN from NetFlow and generate from network files */ + #define NF_AS_BGP 2 /* ignore ASN from NetFlow and generate from BGP peerings */ + + #define NF_NET_COMPAT 0x00000000 /* Backward compatibility selection */ + #define NF_NET_KEEP 0x00000001 /* Determine IP network prefixes from NetFlow data */ + #define NF_NET_NEW 0x00000002 /* Determine IP network prefixes from network files */ + #define NF_NET_BGP 0x00000004 /* Determine IP network prefixes from BGP peerings */ + #define NF_NET_STATIC 0x00000008 /* Determine IP network prefixes from static mask */ + + /* NetFlow V9 stuff */ + #define NF9_TEMPLATE_FLOWSET_ID 0 + #define NF9_OPTIONS_FLOWSET_ID 1 + #define NF9_MIN_RECORD_FLOWSET_ID 256 + #define NF9_MAX_DEFINED_FIELD 384 + + /* Flowset record types the we care about */ + #define NF9_IN_BYTES 1 + #define NF9_IN_PACKETS 2 + #define NF9_FLOWS 3 + #define NF9_L4_PROTOCOL 4 + #define NF9_SRC_TOS 5 + #define NF9_TCP_FLAGS 6 + #define NF9_L4_SRC_PORT 7 + #define NF9_IPV4_SRC_ADDR 8 + #define NF9_SRC_MASK 9 + #define NF9_INPUT_SNMP 10 + #define NF9_L4_DST_PORT 11 + #define NF9_IPV4_DST_ADDR 12 + #define NF9_DST_MASK 13 + #define NF9_OUTPUT_SNMP 14 + #define NF9_IPV4_NEXT_HOP 15 + #define NF9_SRC_AS 16 + #define NF9_DST_AS 17 + #define NF9_BGP_IPV4_NEXT_HOP 18 + #define NF9_MUL_DST_PKTS 19 + #define NF9_MUL_DST_BYTES 20 + /* ... */ + #define NF9_LAST_SWITCHED 21 + #define NF9_FIRST_SWITCHED 22 + #define NF9_OUT_BYTES 23 + #define NF9_OUT_PACKETS 24 + /* ... */ + #define NF9_IPV6_SRC_ADDR 27 + #define NF9_IPV6_DST_ADDR 28 + #define NF9_IPV6_SRC_MASK 29 + #define NF9_IPV6_DST_MASK 30 + #define NF9_ICMP_TYPE 32 + /* ... */ + #define NF9_ENGINE_TYPE 38 + #define NF9_ENGINE_ID 39 + /* ... */ + #define NF9_IN_SRC_MAC 56 + #define NF9_OUT_DST_MAC 57 + /* ... */ + #define NF9_IP_PROTOCOL_VERSION 60 + #define NF9_DIRECTION 61 + #define NF9_IPV6_NEXT_HOP 62 + #define NF9_BGP_IPV6_NEXT_HOP 63 + /* ... */ + #define NF9_MPLS_LABEL_1 70 + #define NF9_MPLS_LABEL_2 71 + #define NF9_MPLS_LABEL_3 72 + #define NF9_MPLS_LABEL_4 73 + #define NF9_MPLS_LABEL_5 74 + #define NF9_MPLS_LABEL_6 75 + #define NF9_MPLS_LABEL_7 76 + #define NF9_MPLS_LABEL_8 77 + #define NF9_MPLS_LABEL_9 78 + #define NF9_MPLS_LABEL_10 79 + #define NF9_IN_DST_MAC 80 + #define NF9_OUT_SRC_MAC 81 + /* ... */ + #define NF9_FLOW_BYTES 85 + /* ... */ + #define NF9_FIRST_SWITCHED_SEC 150 + #define NF9_LAST_SWITCHED_SEC 151 + #define NF9_FIRST_SWITCHED_MSEC 152 + #define NF9_LAST_SWITCHED_MSEC 153 + /* ... */ + #define NF9_UDP_SRC_PORT 180 + #define NF9_UDP_DST_PORT 181 + #define NF9_TCP_SRC_PORT 182 + #define NF9_TCP_DST_PORT 183 + /* ... */ + #define NF9_CUST_TAG 201 + #define NF9_CUST_TAG2 202 + /* ... */ + #define NF9_XLATE_IPV4_SRC_ADDR 225 + #define NF9_XLATE_IPV4_DST_ADDR 226 + #define NF9_XLATE_L4_SRC_PORT 227 + #define NF9_XLATE_L4_DST_PORT 228 + /* ... */ + #define NF9_IN_VLAN 243 + /* ... */ + #define NF9_OUT_VLAN 254 + /* ... */ + #define NF9_XLATE_IPV6_SRC_ADDR 281 + #define NF9_XLATE_IPV6_DST_ADDR 282 + /* ... */ + #define NF9_OBSERVATION_TIME_SEC 322 + #define NF9_OBSERVATION_TIME_MSEC 323 + /* ... */ + #define NF9_ASA_XLATE_IPV4_SRC_ADDR 40001 + #define NF9_ASA_XLATE_IPV4_DST_ADDR 40002 + #define NF9_ASA_XLATE_L4_SRC_PORT 40003 + #define NF9_ASA_XLATE_L4_DST_PORT 40004 + + #define NF9_FTYPE_IPV4 0 + #define NF9_FTYPE_IPV6 1 + #define NF9_FTYPE_VLAN 5 + #define NF9_FTYPE_VLAN_IPV4 5 + #define NF9_FTYPE_VLAN_IPV6 6 + #define NF9_FTYPE_MPLS 10 + #define NF9_FTYPE_MPLS_IPV4 10 + #define NF9_FTYPE_MPLS_IPV6 11 + #define NF9_FTYPE_VLAN_MPLS 15 + #define NF9_FTYPE_VLAN_MPLS_IPV4 15 + #define NF9_FTYPE_VLAN_MPLS_IPV6 16 + + /* Sampling */ + #define NF9_SAMPLING_INTERVAL 34 + #define NF9_SAMPLING_ALGORITHM 35 + #define NF9_FLOW_SAMPLER_ID 48 + #define NF9_FLOW_SAMPLER_MODE 49 + #define NF9_FLOW_SAMPLER_INTERVAL 50 + + /* Classification */ + #define NF9_APPLICATION_DESC 94 + #define NF9_APPLICATION_ID 95 + #define NF9_APPLICATION_NAME 96 + + #define NF9_OPT_SCOPE_SYSTEM 1 + #define NF9_OPT_SCOPE_IF 2 + #define NF9_OPT_SCOPE_LC 3 + #define NF9_OPT_SCOPE_CACHE 4 + #define NF9_OPT_SCOPE_TPL 5 + + #define MAX_TPL_DESC_LIST 81 + static char *tpl_desc_list[] = { + "", + "in bytes", + "in packets", + "flows", + "L4 protocol", + "tos", + "tcp flags", + "L4 src port", + "IPv4 src addr", + "IPv4 src mask", + "input snmp", + "L4 dst port", + "IPv4 dst addr", + "IPv4 dst mask", + "output snmp", + "IPv4 next hop", + "src as", + "dst as", + "BGP IPv4 next hop", + "", "", + "last switched", + "first switched", + "out bytes", + "out packets", + "", "", + "IPv6 src addr", + "IPv6 dst addr", + "IPv6 src mask", + "IPv6 dst mask", + "", + "icmp type", + "", + "sampling interval", + "sampling algorithm", + "", + "", "", "", "", + "", "", "", "", + "", "", "", + "sampler ID", + "sampler mode", + "sampler interval", + "", "", "", "", + "", + "in src mac", + "out dst mac", + "", "", + "ip version", + "direction", + "IPv6 next hop", + "IPv6 BGP next hop", + "", + "", "", "", "", + "", + "mpls label 1", + "mpls label 2", + "mpls label 3", + "mpls label 4", + "mpls label 5", + "mpls label 6", + "mpls label 7", + "mpls label 8", + "mpls label 9", + "mpls label 10", + "in dst mac", + "out src mac" + }; + + #define MAX_OPT_TPL_DESC_LIST 100 + static char *opt_tpl_desc_list[] = { + "", + "scope", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "sampler ID", + "sampler algorithm", "sampler interval", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "", + "", "", "sampler name", + "", "", "", + "", "", "", + "", "", "", + "app desc", "app id", "app name", + "", "", "", + "" + }; + + /* Ordered Template field */ + struct otpl_field { + u_int16_t off; + u_int16_t len; + }; + + struct template_cache_entry { + struct host_addr agent; /* NetFlow Exporter agent */ + u_int32_t source_id; /* Exporter Observation Domain */ + u_int16_t template_id; /* template ID */ + u_int16_t template_type; /* Data = 0, Options = 1 */ + u_int16_t num; /* number of fields described into template */ + u_int16_t len; /* total length of the described flowset */ + struct otpl_field tpl[NF9_MAX_DEFINED_FIELD]; + struct template_cache_entry *next; + }; + + struct template_cache { + u_int16_t num; + struct template_cache_entry *c[TEMPLATE_CACHE_ENTRIES]; + }; + + typedef void (*v8_filter_handler)(struct packet_ptrs *, void *); + struct v8_handler_entry { + u_int8_t max_flows; + u_int8_t exp_size; + v8_filter_handler fh; + }; + + /* functions */ + #if (!defined __NFACCTD_C) + #define EXT extern + #else + #define EXT + #endif + EXT void process_v1_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); + EXT void process_v5_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); + EXT void process_v7_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); + EXT void process_v8_packet(unsigned char *, u_int16_t, struct packet_ptrs *, struct plugin_requests *); + EXT void process_v9_packet(unsigned char *, u_int16_t, struct packet_ptrs_vector *, struct plugin_requests *); + EXT void process_raw_packet(unsigned char *, u_int16_t, struct packet_ptrs_vector *, struct plugin_requests *); + EXT u_int16_t NF_evaluate_flow_type(struct template_cache_entry *, struct packet_ptrs *); + EXT u_int16_t NF_evaluate_direction(struct template_cache_entry *, struct packet_ptrs *); EXT void reset_mac(struct packet_ptrs *); EXT void reset_mac_vlan(struct packet_ptrs *); EXT void reset_ip4(struct packet_ptrs *); @@ -551,6 +700,10 @@ EXT struct template_cache_entry *find_template_v9(u_int16_t, struct packet_ptrs *); EXT struct template_cache_entry *insert_template_v9(struct template_hdr_v9 *, struct packet_ptrs *); EXT void refresh_template_v9(struct template_hdr_v9 *, struct template_cache_entry *, struct packet_ptrs *); +EXT void log_template_v9_header(struct template_cache_entry *, struct packet_ptrs *); +EXT void log_opt_template_v9_field(u_int16_t, u_int16_t, u_int16_t); +EXT void log_template_v9_field(u_int16_t, u_int16_t, u_int16_t); +EXT void log_template_v9_footer(u_int16_t); EXT struct template_cache_entry *insert_opt_template_v9(struct options_template_hdr_v9 *, struct packet_ptrs *); EXT void refresh_opt_template_v9(struct options_template_hdr_v9 *, struct template_cache_entry *, struct packet_ptrs *); #undef EXT diff -Nru pmacct-0.12.1/src/nfprobe_plugin/netflow5.c pmacct-0.12.5/src/nfprobe_plugin/netflow5.c --- pmacct-0.12.1/src/nfprobe_plugin/netflow5.c 2010-03-06 12:10:17.000000000 +0000 +++ pmacct-0.12.5/src/nfprobe_plugin/netflow5.c 2010-10-26 17:06:40.000000000 +0000 @@ -22,13 +22,13 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* $Id: netflow5.c,v 1.7 2010/03/06 12:10:17 paolo Exp $ */ +/* $Id: netflow5.c,v 1.8 2010/10/26 17:06:40 paolo Exp $ */ #include "common.h" #include "treetype.h" #include "nfprobe_plugin.h" -RCSID("$Id: netflow5.c,v 1.7 2010/03/06 12:10:17 paolo Exp $"); +RCSID("$Id: netflow5.c,v 1.8 2010/10/26 17:06:40 paolo Exp $"); /* * This is the Cisco Netflow(tm) version 5 packet format @@ -81,7 +81,7 @@ for(num_packets = offset = j = i = 0; i < num_flows; i++) { if (j >= NF5_MAXFLOWS - 1) { if (verbose_flag) - Log(LOG_DEBUG, "Sending flow packet len = %d\n", offset); + Log(LOG_DEBUG, "DEBUG ( %s/%s ): Sending NetFlow v5 packet: len = %d\n", config.name, config.type, offset); hdr->flows = htons(hdr->flows); errsz = sizeof(err); getsockopt(nfsock, SOL_SOCKET, SO_ERROR, @@ -191,8 +191,7 @@ /* Send any leftovers */ if (j != 0) { if (verbose_flag) - Log(LOG_DEBUG, "Sending v5 flow packet len = %d\n", - offset); + Log(LOG_DEBUG, "DEBUG ( %s/%s ): Sending NetFlow v5 packet: len = %d\n", config.name, config.type, offset); hdr->flows = htons(hdr->flows); errsz = sizeof(err); getsockopt(nfsock, SOL_SOCKET, SO_ERROR, diff -Nru pmacct-0.12.1/src/nfprobe_plugin/netflow9.c pmacct-0.12.5/src/nfprobe_plugin/netflow9.c --- pmacct-0.12.1/src/nfprobe_plugin/netflow9.c 2010-03-06 12:10:17.000000000 +0000 +++ pmacct-0.12.5/src/nfprobe_plugin/netflow9.c 2010-10-26 17:06:40.000000000 +0000 @@ -22,7 +22,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* $Id: netflow9.c,v 1.9 2010/03/06 12:10:17 paolo Exp $ */ +/* $Id: netflow9.c,v 1.18 2010/10/26 17:06:40 paolo Exp $ */ #define __NFPROBE_NETFLOW9_C @@ -79,9 +79,12 @@ /* ... */ #define NF9_SRC_AS 16 #define NF9_DST_AS 17 +#define NF9_BGP_IPV4_NEXT_HOP 18 /* ... */ #define NF9_LAST_SWITCHED 21 #define NF9_FIRST_SWITCHED 22 +#define NF9_OUT_BYTES 23 +#define NF9_OUT_PACKETS 24 /* ... */ #define NF9_IPV6_SRC_ADDR 27 #define NF9_IPV6_DST_ADDR 28 @@ -89,24 +92,37 @@ #define NF9_FLOW_SAMPLER_ID 48 #define NF9_FLOW_SAMPLER_MODE 49 #define NF9_FLOW_SAMPLER_INTERVAL 50 -#define NF9_SRC_MAC 56 -#define NF9_DST_MAC 57 -#define NF9_SRC_VLAN 58 +#define NF9_IN_SRC_MAC 56 // +#define NF9_OUT_DST_MAC 57 /* ... */ #define NF9_IP_PROTOCOL_VERSION 60 +#define NF9_DIRECTION 61 +/* ... */ +#define NF9_BGP_IPV6_NEXT_HOP 63 /* ... */ #define NF9_MPLS_LABEL_1 70 +/* ... */ +#define NF9_IN_DST_MAC 80 // +#define NF9_OUT_SRC_MAC 81 +/* ... */ +#define NF9_FLOW_APPLICATION_DESC 94 +#define NF9_FLOW_APPLICATION_ID 95 +#define NF9_FLOW_APPLICATION_NAME 96 +/* ... */ /* CUSTOM TYPES START HERE */ -#define NF9_CUST_CLASS 200 #define NF9_CUST_TAG 201 #define NF9_CUST_TAG2 202 /* CUSTOM TYPES END HERE */ +/* ... */ +#define NF9_SRC_VLAN 243 +/* ... */ +#define NF9_DST_VLAN 254 /* OPTION SCOPES */ #define NF9_OPT_SCOPE_SYSTEM 1 /* Stuff pertaining to the templates that softflowd uses */ -#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS 34 +#define NF9_SOFTFLOWD_TEMPLATE_NRECORDS 35 struct NF9_SOFTFLOWD_TEMPLATE { struct NF9_TEMPLATE_FLOWSET_HEADER h; struct NF9_TEMPLATE_FLOWSET_RECORD r[NF9_SOFTFLOWD_TEMPLATE_NRECORDS]; @@ -142,19 +158,21 @@ u_int16_t ifindex_in, ifindex_out; u_int32_t bytes, packets, flows; u_int16_t src_port, dst_port; - u_int8_t protocol, tos, tcp_flags, ipproto; + u_int8_t direction, protocol, tos; + u_int8_t tcp_flags, ipproto; as_t src_as, dst_as; u_int8_t src_mac[6], dst_mac[6]; u_int16_t vlan; } __packed; struct NF9_SOFTFLOWD_DATA_V4 { - u_int32_t src_addr, dst_addr; + u_int32_t src_addr, dst_addr, bgp_next_hop; struct NF9_SOFTFLOWD_DATA_COMMON c; } __packed; struct NF9_SOFTFLOWD_DATA_V6 { u_int8_t src_addr[16], dst_addr[16]; + u_int8_t bgp_next_hop[16]; struct NF9_SOFTFLOWD_DATA_COMMON c; } __packed; @@ -168,15 +186,23 @@ static struct NF9_SOFTFLOWD_TEMPLATE v4_template; static struct NF9_INTERNAL_TEMPLATE v4_int_template; +static struct NF9_SOFTFLOWD_TEMPLATE v4_template_out; +static struct NF9_INTERNAL_TEMPLATE v4_int_template_out; static struct NF9_SOFTFLOWD_TEMPLATE v6_template; static struct NF9_INTERNAL_TEMPLATE v6_int_template; -static struct NF9_OPTIONS_TEMPLATE options_template; -static struct NF9_INTERNAL_OPTIONS_TEMPLATE options_int_template; +static struct NF9_SOFTFLOWD_TEMPLATE v6_template_out; +static struct NF9_INTERNAL_TEMPLATE v6_int_template_out; +static struct NF9_OPTIONS_TEMPLATE sampling_option_template; +static struct NF9_INTERNAL_OPTIONS_TEMPLATE sampling_option_int_template; +static struct NF9_OPTIONS_TEMPLATE class_option_template; +static struct NF9_INTERNAL_OPTIONS_TEMPLATE class_option_int_template; static char ftoft_buf_0[sizeof(struct NF9_SOFTFLOWD_DATA_V6)]; static char ftoft_buf_1[sizeof(struct NF9_SOFTFLOWD_DATA_V6)]; static int nf9_pkts_until_template = -1; static u_int8_t send_options = FALSE; +static u_int8_t send_sampling_option = FALSE; +static u_int8_t send_class_option = FALSE; static void flow_to_flowset_input_handler(char *flowset, const struct FLOW *flow, int idx, int size) @@ -197,6 +223,16 @@ } static void +flow_to_flowset_direction_handler(char *flowset, const struct FLOW *flow, int idx, int size) +{ + u_int8_t rec8; + + rec8 = flow->direction[idx] ? (flow->direction[idx]-1) : 0; + + memcpy(flowset, &rec8, size); +} + +static void flow_to_flowset_flows_handler(char *flowset, const struct FLOW *flow, int idx, int size) { u_int32_t rec32; @@ -218,6 +254,12 @@ } static void +flow_to_flowset_bgp_next_hop_v4_handler(char *flowset, const struct FLOW *flow, int idx, int size) +{ + memcpy(flowset, &flow->bgp_next_hop[idx].v4, size); +} + +static void flow_to_flowset_src_nmask_handler(char *flowset, const struct FLOW *flow, int idx, int size) { memcpy(flowset, &flow->mask[idx], size); @@ -242,6 +284,12 @@ } static void +flow_to_flowset_bgp_next_hop_v6_handler(char *flowset, const struct FLOW *flow, int idx, int size) +{ + memcpy(flowset, &flow->bgp_next_hop[idx].v6, size); +} + +static void flow_to_flowset_src_port_handler(char *flowset, const struct FLOW *flow, int idx, int size) { memcpy(flowset, &flow->port[idx], size); @@ -298,10 +346,7 @@ static void flow_to_flowset_vlan_handler(char *flowset, const struct FLOW *flow, int idx, int size) { - u_int16_t rec16; - - rec16 = htons(flow->vlan); - memcpy(flowset, &rec16, size); + memcpy(flowset, &flow->vlan, size); } static void @@ -313,16 +358,7 @@ static void flow_to_flowset_class_handler(char *flowset, const struct FLOW *flow, int idx, int size) { - char buf[MAX_PROTOCOL_LEN+1]; - - memset(buf, 0, MAX_PROTOCOL_LEN+1); - if (flow->class && class[flow->class-1].id) { - strlcpy(buf, class[flow->class-1].protocol, MAX_PROTOCOL_LEN); - buf[sizeof(buf)-1] = '\0'; - } - else strlcpy(buf, "unknown", MAX_PROTOCOL_LEN); - - memcpy(flowset, buf, size); + memcpy(flowset, &flow->class, size); } static void @@ -369,55 +405,88 @@ config.nfprobe_what_to_count |= COUNT_IP_PROTO; config.nfprobe_what_to_count |= COUNT_IP_TOS; } -/* - if ( ! ( config.nfprobe_what_to_count & COUNT_SRC_HOST && - config.nfprobe_what_to_count & COUNT_DST_HOST && - config.nfprobe_what_to_count & COUNT_SRC_PORT && - config.nfprobe_what_to_count & COUNT_DST_PORT && - config.nfprobe_what_to_count & COUNT_IP_PROTO && - config.nfprobe_what_to_count & COUNT_IP_TOS ) ) - config.nfprobe_what_to_count |= COUNT_FLOWS; -*/ rcount = 0; bzero(&v4_template, sizeof(v4_template)); bzero(&v4_int_template, sizeof(v4_int_template)); + bzero(&v4_template_out, sizeof(v4_template_out)); + bzero(&v4_int_template_out, sizeof(v4_int_template_out)); v4_template.r[rcount].type = htons(NF9_LAST_SWITCHED); v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_LAST_SWITCHED); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].length = 4; rcount++; v4_template.r[rcount].type = htons(NF9_FIRST_SWITCHED); v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_FIRST_SWITCHED); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].length = 4; rcount++; v4_template.r[rcount].type = htons(NF9_IN_BYTES); v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].length = 4; + // Cisco doesn't appear to do that (yet?) + // v4_template_out.r[rcount].type = htons(NF9_OUT_BYTES); + v4_template_out.r[rcount].type = htons(NF9_IN_BYTES); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].length = 4; rcount++; v4_template.r[rcount].type = htons(NF9_IN_PACKETS); v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].length = 4; + // Cisco doesn't appear to do that (yet?) + // v4_template_out.r[rcount].type = htons(NF9_OUT_PACKETS); + v4_template_out.r[rcount].type = htons(NF9_IN_PACKETS); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].length = 4; rcount++; v4_template.r[rcount].type = htons(NF9_IP_PROTOCOL_VERSION); v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_IP_PROTOCOL_VERSION); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].length = 1; rcount++; v4_template.r[rcount].type = htons(NF9_INPUT_SNMP); v4_template.r[rcount].length = htons(2); v4_int_template.r[rcount].handler = flow_to_flowset_input_handler; v4_int_template.r[rcount].length = 2; + v4_template_out.r[rcount].type = htons(NF9_INPUT_SNMP); + v4_template_out.r[rcount].length = htons(2); + v4_int_template_out.r[rcount].handler = flow_to_flowset_input_handler; + v4_int_template_out.r[rcount].length = 2; rcount++; v4_template.r[rcount].type = htons(NF9_OUTPUT_SNMP); v4_template.r[rcount].length = htons(2); v4_int_template.r[rcount].handler = flow_to_flowset_output_handler; v4_int_template.r[rcount].length = 2; + v4_template_out.r[rcount].type = htons(NF9_OUTPUT_SNMP); + v4_template_out.r[rcount].length = htons(2); + v4_int_template_out.r[rcount].handler = flow_to_flowset_output_handler; + v4_int_template_out.r[rcount].length = 2; + rcount++; + v4_template.r[rcount].type = htons(NF9_DIRECTION); + v4_template.r[rcount].length = htons(1); + v4_int_template.r[rcount].handler = flow_to_flowset_direction_handler; + v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_DIRECTION); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_direction_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; if (config.nfprobe_what_to_count & COUNT_FLOWS) { v4_template.r[rcount].type = htons(NF9_FLOWS); v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_flows_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_FLOWS); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_flows_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_HOST) { @@ -425,6 +494,10 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_src_host_v4_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_IPV4_SRC_ADDR); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_src_host_v4_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_HOST) { @@ -432,13 +505,32 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_dst_host_v4_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_IPV4_DST_ADDR); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_dst_host_v4_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } + if (config.nfprobe_what_to_count & COUNT_PEER_DST_IP) { + v4_template.r[rcount].type = htons(NF9_BGP_IPV4_NEXT_HOP); + v4_template.r[rcount].length = htons(4); + v4_int_template.r[rcount].handler = flow_to_flowset_bgp_next_hop_v4_handler; + v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_BGP_IPV4_NEXT_HOP); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_bgp_next_hop_v4_handler; + v4_int_template_out.r[rcount].length = 4; + rcount++; + } if (config.nfprobe_what_to_count & COUNT_SRC_NMASK) { v4_template.r[rcount].type = htons(NF9_SRC_MASK); v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_src_nmask_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_SRC_MASK); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_src_nmask_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_NMASK) { @@ -446,6 +538,10 @@ v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_dst_nmask_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_DST_MASK); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_dst_nmask_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_PORT) { @@ -453,6 +549,10 @@ v4_template.r[rcount].length = htons(2); v4_int_template.r[rcount].handler = flow_to_flowset_src_port_handler; v4_int_template.r[rcount].length = 2; + v4_template_out.r[rcount].type = htons(NF9_L4_SRC_PORT); + v4_template_out.r[rcount].length = htons(2); + v4_int_template_out.r[rcount].handler = flow_to_flowset_src_port_handler; + v4_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_PORT) { @@ -460,6 +560,10 @@ v4_template.r[rcount].length = htons(2); v4_int_template.r[rcount].handler = flow_to_flowset_dst_port_handler; v4_int_template.r[rcount].length = 2; + v4_template_out.r[rcount].type = htons(NF9_L4_DST_PORT); + v4_template_out.r[rcount].length = htons(2); + v4_int_template_out.r[rcount].handler = flow_to_flowset_dst_port_handler; + v4_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & (COUNT_IP_TOS)) { @@ -467,6 +571,10 @@ v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_ip_tos_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_SRC_TOS); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_ip_tos_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & (COUNT_SRC_PORT|COUNT_DST_PORT)) { @@ -474,6 +582,10 @@ v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_tcp_flags_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_TCP_FLAGS); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_tcp_flags_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_IP_PROTO) { @@ -481,6 +593,10 @@ v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_ip_proto_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_IN_PROTOCOL); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_ip_proto_handler; + v4_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_AS) { @@ -488,6 +604,10 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_src_as_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_SRC_AS); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_src_as_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_AS) { @@ -495,20 +615,32 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_dst_as_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_DST_AS); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_dst_as_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_MAC) { - v4_template.r[rcount].type = htons(NF9_SRC_MAC); + v4_template.r[rcount].type = htons(NF9_IN_SRC_MAC); v4_template.r[rcount].length = htons(6); v4_int_template.r[rcount].handler = flow_to_flowset_src_mac_handler; v4_int_template.r[rcount].length = 6; + v4_template_out.r[rcount].type = htons(NF9_OUT_SRC_MAC); + v4_template_out.r[rcount].length = htons(6); + v4_int_template_out.r[rcount].handler = flow_to_flowset_src_mac_handler; + v4_int_template_out.r[rcount].length = 6; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_MAC) { - v4_template.r[rcount].type = htons(NF9_DST_MAC); + v4_template.r[rcount].type = htons(NF9_IN_DST_MAC); v4_template.r[rcount].length = htons(6); v4_int_template.r[rcount].handler = flow_to_flowset_dst_mac_handler; v4_int_template.r[rcount].length = 6; + v4_template_out.r[rcount].type = htons(NF9_OUT_DST_MAC); + v4_template_out.r[rcount].length = htons(6); + v4_int_template_out.r[rcount].handler = flow_to_flowset_dst_mac_handler; + v4_int_template_out.r[rcount].length = 6; rcount++; } if (config.nfprobe_what_to_count & COUNT_VLAN) { @@ -516,20 +648,10 @@ v4_template.r[rcount].length = htons(2); v4_int_template.r[rcount].handler = flow_to_flowset_vlan_handler; v4_int_template.r[rcount].length = 2; - rcount++; - } - if (config.nfprobe_what_to_count & COUNT_VLAN) { - v4_template.r[rcount].type = htons(NF9_MPLS_LABEL_1); - v4_template.r[rcount].length = htons(3); - v4_int_template.r[rcount].handler = flow_to_flowset_mpls_handler; - v4_int_template.r[rcount].length = 3; - rcount++; - } - if (config.nfprobe_what_to_count & COUNT_CLASS) { - v4_template.r[rcount].type = htons(NF9_CUST_CLASS); - v4_template.r[rcount].length = htons(16); - v4_int_template.r[rcount].handler = flow_to_flowset_class_handler; - v4_int_template.r[rcount].length = 16; + v4_template_out.r[rcount].type = htons(NF9_DST_VLAN); + v4_template_out.r[rcount].length = htons(2); + v4_int_template_out.r[rcount].handler = flow_to_flowset_vlan_handler; + v4_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & COUNT_ID) { @@ -537,6 +659,10 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_tag_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_CUST_TAG); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_tag_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_ID2) { @@ -544,6 +670,10 @@ v4_template.r[rcount].length = htons(4); v4_int_template.r[rcount].handler = flow_to_flowset_tag2_handler; v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_CUST_TAG2); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_tag2_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } if (config.sampling_rate || config.ext_sampling_rate) { @@ -551,6 +681,21 @@ v4_template.r[rcount].length = htons(1); v4_int_template.r[rcount].handler = flow_to_flowset_sampler_id_handler; v4_int_template.r[rcount].length = 1; + v4_template_out.r[rcount].type = htons(NF9_FLOW_SAMPLER_ID); + v4_template_out.r[rcount].length = htons(1); + v4_int_template_out.r[rcount].handler = flow_to_flowset_sampler_id_handler; + v4_int_template_out.r[rcount].length = 1; + rcount++; + } + if (config.nfprobe_what_to_count & COUNT_CLASS) { + v4_template.r[rcount].type = htons(NF9_FLOW_APPLICATION_ID); + v4_template.r[rcount].length = htons(4); + v4_int_template.r[rcount].handler = flow_to_flowset_class_handler; + v4_int_template.r[rcount].length = 4; + v4_template_out.r[rcount].type = htons(NF9_FLOW_APPLICATION_ID); + v4_template_out.r[rcount].length = htons(4); + v4_int_template_out.r[rcount].handler = flow_to_flowset_class_handler; + v4_int_template_out.r[rcount].length = 4; rcount++; } v4_template.h.c.flowset_id = htons(0); @@ -559,50 +704,100 @@ v4_template.h.count = htons(rcount); v4_template.tot_len = sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + v4_template_out.h.c.flowset_id = htons(0); + v4_template_out.h.c.length = htons( sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount) ); + v4_template_out.h.template_id = htons(NF9_SOFTFLOWD_V4_TEMPLATE_ID + config.nfprobe_id + 1); + v4_template_out.h.count = htons(rcount); + v4_template_out.tot_len = sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + assert(rcount < NF9_SOFTFLOWD_TEMPLATE_NRECORDS); - for (idx = 0, v4_int_template.tot_rec_len = 0; idx < rcount; idx++) + for (idx = 0, v4_int_template.tot_rec_len = 0, v4_int_template_out.tot_rec_len = 0; idx < rcount; idx++) { v4_int_template.tot_rec_len += v4_int_template.r[idx].length; + v4_int_template_out.tot_rec_len += v4_int_template_out.r[idx].length; + } rcount = 0; bzero(&v6_template, sizeof(v6_template)); bzero(&v6_int_template, sizeof(v6_int_template)); + bzero(&v6_template_out, sizeof(v6_template_out)); + bzero(&v6_int_template_out, sizeof(v6_int_template_out)); v6_template.r[rcount].type = htons(NF9_LAST_SWITCHED); v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_LAST_SWITCHED); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].length = 4; rcount++; v6_template.r[rcount].type = htons(NF9_FIRST_SWITCHED); v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_FIRST_SWITCHED); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].length = 4; rcount++; v6_template.r[rcount].type = htons(NF9_IN_BYTES); v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].length = 4; + // Cisco doesn't appear to do that (yet?) + // v6_template_out.r[rcount].type = htons(NF9_OUT_BYTES); + v6_template_out.r[rcount].type = htons(NF9_IN_BYTES); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].length = 4; rcount++; v6_template.r[rcount].type = htons(NF9_IN_PACKETS); v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].length = 4; + // Cisco doesn't appear to do that (yet?) + // v6_template_out.r[rcount].type = htons(NF9_OUT_PACKETS); + v6_template_out.r[rcount].type = htons(NF9_IN_PACKETS); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].length = 4; rcount++; v6_template.r[rcount].type = htons(NF9_IP_PROTOCOL_VERSION); v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_IP_PROTOCOL_VERSION); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].length = 1; rcount++; v6_template.r[rcount].type = htons(NF9_INPUT_SNMP); v6_template.r[rcount].length = htons(2); v6_int_template.r[rcount].handler = flow_to_flowset_input_handler; v6_int_template.r[rcount].length = 2; + v6_template_out.r[rcount].type = htons(NF9_INPUT_SNMP); + v6_template_out.r[rcount].length = htons(2); + v6_int_template_out.r[rcount].handler = flow_to_flowset_input_handler; + v6_int_template_out.r[rcount].length = 2; rcount++; v6_template.r[rcount].type = htons(NF9_OUTPUT_SNMP); v6_template.r[rcount].length = htons(2); v6_int_template.r[rcount].handler = flow_to_flowset_output_handler; v6_int_template.r[rcount].length = 2; + v6_template_out.r[rcount].type = htons(NF9_OUTPUT_SNMP); + v6_template_out.r[rcount].length = htons(2); + v6_int_template_out.r[rcount].handler = flow_to_flowset_output_handler; + v6_int_template_out.r[rcount].length = 2; + rcount++; + v6_template.r[rcount].type = htons(NF9_DIRECTION); + v6_template.r[rcount].length = htons(1); + v6_int_template.r[rcount].handler = flow_to_flowset_direction_handler; + v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_DIRECTION); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_direction_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; if (config.nfprobe_what_to_count & COUNT_FLOWS) { v6_template.r[rcount].type = htons(NF9_FLOWS); v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].handler = flow_to_flowset_flows_handler; v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_FLOWS); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_flows_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_HOST) { @@ -610,6 +805,10 @@ v6_template.r[rcount].length = htons(16); v6_int_template.r[rcount].handler = flow_to_flowset_src_host_v6_handler; v6_int_template.r[rcount].length = 16; + v6_template_out.r[rcount].type = htons(NF9_IPV6_SRC_ADDR); + v6_template_out.r[rcount].length = htons(16); + v6_int_template_out.r[rcount].handler = flow_to_flowset_src_host_v6_handler; + v6_int_template_out.r[rcount].length = 16; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_HOST) { @@ -617,13 +816,32 @@ v6_template.r[rcount].length = htons(16); v6_int_template.r[rcount].handler = flow_to_flowset_dst_host_v6_handler; v6_int_template.r[rcount].length = 16; + v6_template_out.r[rcount].type = htons(NF9_IPV6_DST_ADDR); + v6_template_out.r[rcount].length = htons(16); + v6_int_template_out.r[rcount].handler = flow_to_flowset_dst_host_v6_handler; + v6_int_template_out.r[rcount].length = 16; rcount++; } + if (config.nfprobe_what_to_count & COUNT_PEER_DST_IP) { + v6_template.r[rcount].type = htons(NF9_BGP_IPV6_NEXT_HOP); + v6_template.r[rcount].length = htons(16); + v6_int_template.r[rcount].handler = flow_to_flowset_bgp_next_hop_v6_handler; + v6_int_template.r[rcount].length = 16; + v6_template_out.r[rcount].type = htons(NF9_BGP_IPV6_NEXT_HOP); + v6_template_out.r[rcount].length = htons(16); + v6_int_template_out.r[rcount].handler = flow_to_flowset_bgp_next_hop_v6_handler; + v6_int_template_out.r[rcount].length = 16; + rcount++; + } if (config.nfprobe_what_to_count & COUNT_SRC_NMASK) { v6_template.r[rcount].type = htons(NF9_SRC_MASK); v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_src_nmask_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_SRC_MASK); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_src_nmask_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_NMASK) { @@ -631,6 +849,10 @@ v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_dst_nmask_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_DST_MASK); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_dst_nmask_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & (COUNT_IP_TOS)) { @@ -638,6 +860,10 @@ v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_ip_tos_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_SRC_TOS); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_ip_tos_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_PORT) { @@ -645,6 +871,10 @@ v6_template.r[rcount].length = htons(2); v6_int_template.r[rcount].handler = flow_to_flowset_src_port_handler; v6_int_template.r[rcount].length = 2; + v6_template_out.r[rcount].type = htons(NF9_L4_SRC_PORT); + v6_template_out.r[rcount].length = htons(2); + v6_int_template_out.r[rcount].handler = flow_to_flowset_src_port_handler; + v6_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_PORT) { @@ -652,6 +882,10 @@ v6_template.r[rcount].length = htons(2); v6_int_template.r[rcount].handler = flow_to_flowset_dst_port_handler; v6_int_template.r[rcount].length = 2; + v6_template_out.r[rcount].type = htons(NF9_L4_DST_PORT); + v6_template_out.r[rcount].length = htons(2); + v6_int_template_out.r[rcount].handler = flow_to_flowset_dst_port_handler; + v6_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & (COUNT_SRC_PORT|COUNT_DST_PORT)) { @@ -659,6 +893,10 @@ v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_tcp_flags_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_TCP_FLAGS); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_tcp_flags_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_IP_PROTO) { @@ -666,6 +904,10 @@ v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_ip_proto_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_IN_PROTOCOL); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_ip_proto_handler; + v6_int_template_out.r[rcount].length = 1; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_AS) { @@ -673,6 +915,10 @@ v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].handler = flow_to_flowset_src_as_handler; v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_SRC_AS); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_src_as_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_AS) { @@ -680,20 +926,32 @@ v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].handler = flow_to_flowset_dst_as_handler; v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_DST_AS); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_dst_as_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_SRC_MAC) { - v6_template.r[rcount].type = htons(NF9_SRC_MAC); + v6_template.r[rcount].type = htons(NF9_IN_SRC_MAC); v6_template.r[rcount].length = htons(6); v6_int_template.r[rcount].handler = flow_to_flowset_src_mac_handler; v6_int_template.r[rcount].length = 6; + v6_template_out.r[rcount].type = htons(NF9_OUT_SRC_MAC); + v6_template_out.r[rcount].length = htons(6); + v6_int_template_out.r[rcount].handler = flow_to_flowset_src_mac_handler; + v6_int_template_out.r[rcount].length = 6; rcount++; } if (config.nfprobe_what_to_count & COUNT_DST_MAC) { - v6_template.r[rcount].type = htons(NF9_DST_MAC); + v6_template.r[rcount].type = htons(NF9_IN_DST_MAC); v6_template.r[rcount].length = htons(6); v6_int_template.r[rcount].handler = flow_to_flowset_dst_mac_handler; v6_int_template.r[rcount].length = 6; + v6_template_out.r[rcount].type = htons(NF9_OUT_DST_MAC); + v6_template_out.r[rcount].length = htons(6); + v6_int_template_out.r[rcount].handler = flow_to_flowset_dst_mac_handler; + v6_int_template_out.r[rcount].length = 6; rcount++; } if (config.nfprobe_what_to_count & COUNT_VLAN) { @@ -701,20 +959,10 @@ v6_template.r[rcount].length = htons(2); v6_int_template.r[rcount].handler = flow_to_flowset_vlan_handler; v6_int_template.r[rcount].length = 2; - rcount++; - } - if (config.nfprobe_what_to_count & COUNT_VLAN) { - v6_template.r[rcount].type = htons(NF9_MPLS_LABEL_1); - v6_template.r[rcount].length = htons(3); - v6_int_template.r[rcount].handler = flow_to_flowset_mpls_handler; - v6_int_template.r[rcount].length = 3; - rcount++; - } - if (config.nfprobe_what_to_count & COUNT_CLASS) { - v6_template.r[rcount].type = htons(NF9_CUST_CLASS); - v6_template.r[rcount].length = htons(16); - v6_int_template.r[rcount].handler = flow_to_flowset_class_handler; - v6_int_template.r[rcount].length = 16; + v6_template_out.r[rcount].type = htons(NF9_DST_VLAN); + v6_template_out.r[rcount].length = htons(2); + v6_int_template_out.r[rcount].handler = flow_to_flowset_vlan_handler; + v6_int_template_out.r[rcount].length = 2; rcount++; } if (config.nfprobe_what_to_count & COUNT_ID) { @@ -722,6 +970,10 @@ v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].handler = flow_to_flowset_tag_handler; v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_CUST_TAG); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_tag_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } if (config.nfprobe_what_to_count & COUNT_ID2) { @@ -729,6 +981,10 @@ v6_template.r[rcount].length = htons(4); v6_int_template.r[rcount].handler = flow_to_flowset_tag2_handler; v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_CUST_TAG2); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_tag2_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } if (config.sampling_rate || config.ext_sampling_rate) { @@ -736,6 +992,21 @@ v6_template.r[rcount].length = htons(1); v6_int_template.r[rcount].handler = flow_to_flowset_sampler_id_handler; v6_int_template.r[rcount].length = 1; + v6_template_out.r[rcount].type = htons(NF9_FLOW_SAMPLER_ID); + v6_template_out.r[rcount].length = htons(1); + v6_int_template_out.r[rcount].handler = flow_to_flowset_sampler_id_handler; + v6_int_template_out.r[rcount].length = 1; + rcount++; + } + if (config.nfprobe_what_to_count & COUNT_CLASS) { + v6_template.r[rcount].type = htons(NF9_FLOW_APPLICATION_ID); + v6_template.r[rcount].length = htons(4); + v6_int_template.r[rcount].handler = flow_to_flowset_class_handler; + v6_int_template.r[rcount].length = 4; + v6_template_out.r[rcount].type = htons(NF9_FLOW_APPLICATION_ID); + v6_template_out.r[rcount].length = htons(4); + v6_int_template_out.r[rcount].handler = flow_to_flowset_class_handler; + v6_int_template_out.r[rcount].length = 4; rcount++; } v6_template.h.c.flowset_id = htons(0); @@ -744,129 +1015,241 @@ v6_template.h.count = htons(rcount); v6_template.tot_len = sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + v6_template_out.h.c.flowset_id = htons(0); + v6_template_out.h.c.length = htons( sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount) ); + v6_template_out.h.template_id = htons(NF9_SOFTFLOWD_V6_TEMPLATE_ID + config.nfprobe_id + 1); + v6_template_out.h.count = htons(rcount); + v6_template_out.tot_len = sizeof(struct NF9_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + assert(rcount < NF9_SOFTFLOWD_TEMPLATE_NRECORDS); - for (idx = 0, v6_int_template.tot_rec_len = 0; idx < rcount; idx++) + for (idx = 0, v6_int_template.tot_rec_len = 0, v6_int_template_out.tot_rec_len = 0; idx < rcount; idx++) { v6_int_template.tot_rec_len += v6_int_template.r[idx].length; + v6_int_template_out.tot_rec_len += v6_int_template_out.r[idx].length; + } } static void nf9_init_options_template(void) { - int rcount, idx; + int rcount, idx, slen = 0; - rcount = 0; - bzero(&options_template, sizeof(options_template)); - bzero(&options_int_template, sizeof(options_int_template)); + switch (config.nfprobe_source_ha.family) { + case AF_INET: + slen = 4; + break; + case AF_INET6: + slen = 16; + break; + default: + slen = 4; + break; + } - options_template.r[rcount].type = htons(NF9_OPT_SCOPE_SYSTEM); - options_template.r[rcount].length = htons(0); - options_int_template.r[rcount].length = 0; + rcount = 0; + bzero(&sampling_option_template, sizeof(sampling_option_template)); + bzero(&sampling_option_int_template, sizeof(sampling_option_int_template)); + + sampling_option_template.r[rcount].type = htons(NF9_OPT_SCOPE_SYSTEM); + sampling_option_template.r[rcount].length = htons(slen); + sampling_option_int_template.r[rcount].length = slen; + rcount++; + sampling_option_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_ID); + sampling_option_template.r[rcount].length = htons(1); + sampling_option_int_template.r[rcount].length = 1; + rcount++; + sampling_option_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_MODE); + sampling_option_template.r[rcount].length = htons(1); + sampling_option_int_template.r[rcount].length = 1; rcount++; - options_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_ID); - options_template.r[rcount].length = htons(1); - options_int_template.r[rcount].length = 1; + sampling_option_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_INTERVAL); + sampling_option_template.r[rcount].length = htons(4); + sampling_option_int_template.r[rcount].length = 4; rcount++; - options_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_MODE); - options_template.r[rcount].length = htons(1); - options_int_template.r[rcount].length = 1; + sampling_option_template.h.c.flowset_id = htons(1); + sampling_option_template.h.c.length = htons( sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount) ); + sampling_option_template.h.template_id = htons(NF9_OPTIONS_TEMPLATE_ID + config.nfprobe_id ); + sampling_option_template.h.scope_len = htons(4); /* NF9_OPT_SCOPE_SYSTEM */ + sampling_option_template.h.option_len = htons(12); /* NF9_FLOW_SAMPLER_ID + NF9_FLOW_SAMPLER_MODE + NF9_FLOW_SAMPLER_INTERVAL */ + sampling_option_template.tot_len = sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + + for (idx = 0, sampling_option_int_template.tot_rec_len = 0; idx < rcount; idx++) + sampling_option_int_template.tot_rec_len += sampling_option_int_template.r[idx].length; + + rcount = 0; + bzero(&class_option_template, sizeof(class_option_template)); + bzero(&class_option_int_template, sizeof(class_option_int_template)); + + class_option_template.r[rcount].type = htons(NF9_OPT_SCOPE_SYSTEM); + class_option_template.r[rcount].length = htons(4); + class_option_int_template.r[rcount].length = 4; rcount++; - options_template.r[rcount].type = htons(NF9_FLOW_SAMPLER_INTERVAL); - options_template.r[rcount].length = htons(4); - options_int_template.r[rcount].length = 4; + class_option_template.r[rcount].type = htons(NF9_FLOW_APPLICATION_ID); + class_option_template.r[rcount].length = htons(4); + class_option_int_template.r[rcount].length = 4; rcount++; - options_template.h.c.flowset_id = htons(1); - options_template.h.c.length = htons( sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount) ); - options_template.h.template_id = htons(NF9_OPTIONS_TEMPLATE_ID + config.nfprobe_id ); - options_template.h.scope_len = htons(4); /* NF9_OPT_SCOPE_SYSTEM */ - options_template.h.option_len = htons(12); /* NF9_FLOW_SAMPLER_ID + NF9_FLOW_SAMPLER_MODE + NF9_FLOW_SAMPLER_INTERVAL */ - options_template.tot_len = sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); + class_option_template.r[rcount].type = htons(NF9_FLOW_APPLICATION_NAME); + class_option_template.r[rcount].length = htons(16); + class_option_int_template.r[rcount].length = 16; + rcount++; + class_option_template.h.c.flowset_id = htons(1); + class_option_template.h.c.length = htons( sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount) ); + class_option_template.h.template_id = htons(NF9_OPTIONS_TEMPLATE_ID + 1 + config.nfprobe_id ); + class_option_template.h.scope_len = htons(4); /* NF9_OPT_SCOPE_SYSTEM */ + class_option_template.h.option_len = htons(8); /* NF9_FLOW_APPLICATION_ID + NF9_FLOW_APPLICATION_NAME */ + class_option_template.tot_len = sizeof(struct NF9_OPTIONS_TEMPLATE_FLOWSET_HEADER) + (sizeof(struct NF9_TEMPLATE_FLOWSET_RECORD) * rcount); - for (idx = 0, options_int_template.tot_rec_len = 0; idx < rcount; idx++) - options_int_template.tot_rec_len += options_int_template.r[idx].length; + for (idx = 0, class_option_int_template.tot_rec_len = 0; idx < rcount; idx++) + class_option_int_template.tot_rec_len += class_option_int_template.r[idx].length; } static int nf_flow_to_flowset(const struct FLOW *flow, u_char *packet, u_int len, - const struct timeval *system_boot_time, u_int *len_used) + const struct timeval *system_boot_time, u_int *len_used, int direction) { u_int freclen, ret_len, nflows, idx; u_int32_t rec32; u_int8_t rec8; char *ftoft_ptr_0 = ftoft_buf_0; char *ftoft_ptr_1 = ftoft_buf_1; + int flow_direction[2]; bzero(ftoft_buf_0, sizeof(ftoft_buf_0)); bzero(ftoft_buf_1, sizeof(ftoft_buf_1)); *len_used = nflows = ret_len = 0; - - rec32 = htonl(timeval_sub_ms(&flow->flow_last, system_boot_time)); - memcpy(ftoft_ptr_0, &rec32, 4); - memcpy(ftoft_ptr_1, &rec32, 4); - ftoft_ptr_0 += 4; - ftoft_ptr_1 += 4; - - rec32 = htonl(timeval_sub_ms(&flow->flow_start, system_boot_time)); - memcpy(ftoft_ptr_0, &rec32, 4); - memcpy(ftoft_ptr_1, &rec32, 4); - ftoft_ptr_0 += 4; - ftoft_ptr_1 += 4; - - rec32 = htonl(flow->octets[0]); - memcpy(ftoft_ptr_0, &rec32, 4); - rec32 = htonl(flow->octets[1]); - memcpy(ftoft_ptr_1, &rec32, 4); - ftoft_ptr_0 += 4; - ftoft_ptr_1 += 4; + flow_direction[0] = (flow->direction[0] == DIRECTION_UNKNOWN) ? DIRECTION_IN : flow->direction[0]; + flow_direction[1] = (flow->direction[1] == DIRECTION_UNKNOWN) ? DIRECTION_IN : flow->direction[1]; - rec32 = htonl(flow->packets[0]); - memcpy(ftoft_ptr_0, &rec32, 4); - rec32 = htonl(flow->packets[1]); - memcpy(ftoft_ptr_1, &rec32, 4); - ftoft_ptr_0 += 4; - ftoft_ptr_1 += 4; + if (direction == flow_direction[0]) { + rec32 = htonl(timeval_sub_ms(&flow->flow_last, system_boot_time)); + memcpy(ftoft_ptr_0, &rec32, 4); + ftoft_ptr_0 += 4; + + rec32 = htonl(timeval_sub_ms(&flow->flow_start, system_boot_time)); + memcpy(ftoft_ptr_0, &rec32, 4); + ftoft_ptr_0 += 4; + + rec32 = htonl(flow->octets[0]); + memcpy(ftoft_ptr_0, &rec32, 4); + ftoft_ptr_0 += 4; + + rec32 = htonl(flow->packets[0]); + memcpy(ftoft_ptr_0, &rec32, 4); + ftoft_ptr_0 += 4; + + switch (flow->af) { + case AF_INET: + rec8 = 4; + memcpy(ftoft_ptr_0, &rec8, 1); + ftoft_ptr_0 += 1; + if (flow_direction[0] == DIRECTION_IN) { + for (idx = 5; v4_int_template.r[idx].length; idx++) { + v4_int_template.r[idx].handler(ftoft_ptr_0, flow, 0, v4_int_template.r[idx].length); + ftoft_ptr_0 += v4_int_template.r[idx].length; + } + freclen = v4_int_template.tot_rec_len; + } + else if (flow_direction[0] == DIRECTION_OUT) { + for (idx = 5; v4_int_template_out.r[idx].length; idx++) { + v4_int_template_out.r[idx].handler(ftoft_ptr_0, flow, 0, v4_int_template_out.r[idx].length); + ftoft_ptr_0 += v4_int_template_out.r[idx].length; + } + freclen = v4_int_template_out.tot_rec_len; + } + break; + case AF_INET6: + rec8 = 6; + memcpy(ftoft_ptr_0, &rec8, 1); + ftoft_ptr_0 += 1; + if (flow_direction[0] == DIRECTION_IN) { + for (idx = 5; v6_int_template.r[idx].length; idx++) { + v6_int_template.r[idx].handler(ftoft_ptr_0, flow, 0, v6_int_template.r[idx].length); + ftoft_ptr_0 += v6_int_template.r[idx].length; + } + freclen = v6_int_template.tot_rec_len; + } + else if (flow_direction[0] == DIRECTION_OUT) { + for (idx = 5; v6_int_template_out.r[idx].length; idx++) { + v6_int_template_out.r[idx].handler(ftoft_ptr_0, flow, 0, v6_int_template_out.r[idx].length); + ftoft_ptr_0 += v6_int_template_out.r[idx].length; + } + freclen = v6_int_template_out.tot_rec_len; + } + break; + default: + return (-1); + } + } - switch (flow->af) { - case AF_INET: - rec8 = 4; - memcpy(ftoft_ptr_0, &rec8, 1); - memcpy(ftoft_ptr_1, &rec8, 1); - ftoft_ptr_0 += 1; - ftoft_ptr_1 += 1; - for (idx = 5; v4_int_template.r[idx].length; idx++) { - v4_int_template.r[idx].handler(ftoft_ptr_0, flow, 0, v4_int_template.r[idx].length); - v4_int_template.r[idx].handler(ftoft_ptr_1, flow, 1, v4_int_template.r[idx].length); - ftoft_ptr_0 += v4_int_template.r[idx].length; - ftoft_ptr_1 += v4_int_template.r[idx].length; + if (direction == flow_direction[1]) { + rec32 = htonl(timeval_sub_ms(&flow->flow_last, system_boot_time)); + memcpy(ftoft_ptr_1, &rec32, 4); + ftoft_ptr_1 += 4; + + rec32 = htonl(timeval_sub_ms(&flow->flow_start, system_boot_time)); + memcpy(ftoft_ptr_1, &rec32, 4); + ftoft_ptr_1 += 4; + + rec32 = htonl(flow->octets[1]); + memcpy(ftoft_ptr_1, &rec32, 4); + ftoft_ptr_1 += 4; + + rec32 = htonl(flow->packets[1]); + memcpy(ftoft_ptr_1, &rec32, 4); + ftoft_ptr_1 += 4; + + switch (flow->af) { + case AF_INET: + rec8 = 4; + memcpy(ftoft_ptr_1, &rec8, 1); + ftoft_ptr_1 += 1; + if (flow_direction[1] == DIRECTION_IN) { + for (idx = 5; v4_int_template.r[idx].length; idx++) { + v4_int_template.r[idx].handler(ftoft_ptr_1, flow, 1, v4_int_template.r[idx].length); + ftoft_ptr_1 += v4_int_template.r[idx].length; + } + freclen = v4_int_template.tot_rec_len; } - freclen = v4_int_template.tot_rec_len; - break; - case AF_INET6: - rec8 = 6; - memcpy(ftoft_ptr_0, &rec8, 1); - memcpy(ftoft_ptr_1, &rec8, 1); - ftoft_ptr_0 += 1; - ftoft_ptr_1 += 1; - for (idx = 5; v6_int_template.r[idx].length; idx++) { - v6_int_template.r[idx].handler(ftoft_ptr_0, flow, 0, v6_int_template.r[idx].length); - v6_int_template.r[idx].handler(ftoft_ptr_1, flow, 1, v6_int_template.r[idx].length); - ftoft_ptr_0 += v6_int_template.r[idx].length; - ftoft_ptr_1 += v6_int_template.r[idx].length; + else if (flow_direction[1] == DIRECTION_OUT) { + for (idx = 5; v4_int_template_out.r[idx].length; idx++) { + v4_int_template_out.r[idx].handler(ftoft_ptr_1, flow, 1, v4_int_template_out.r[idx].length); + ftoft_ptr_1 += v4_int_template_out.r[idx].length; + } + freclen = v4_int_template_out.tot_rec_len; } - freclen = v6_int_template.tot_rec_len; - break; - default: - return (-1); + break; + case AF_INET6: + rec8 = 6; + memcpy(ftoft_ptr_1, &rec8, 1); + ftoft_ptr_1 += 1; + if (flow_direction[1] == DIRECTION_IN) { + for (idx = 5; v6_int_template.r[idx].length; idx++) { + v6_int_template.r[idx].handler(ftoft_ptr_1, flow, 1, v6_int_template.r[idx].length); + ftoft_ptr_1 += v6_int_template.r[idx].length; + } + freclen = v6_int_template.tot_rec_len; + } + else if (flow_direction[1] == DIRECTION_OUT) { + for (idx = 5; v6_int_template_out.r[idx].length; idx++) { + v6_int_template_out.r[idx].handler(ftoft_ptr_1, flow, 1, v6_int_template_out.r[idx].length); + ftoft_ptr_1 += v6_int_template_out.r[idx].length; + } + freclen = v6_int_template_out.tot_rec_len; + } + break; + default: + return (-1); + } } - if (flow->octets[0] > 0) { + if (flow->octets[0] > 0 && direction == flow_direction[0]) { if (ret_len + freclen > len) return (-1); memcpy(packet + ret_len, ftoft_buf_0, freclen); ret_len += freclen; nflows++; } - if (flow->octets[1] > 0) { + if (flow->octets[1] > 0 && direction == flow_direction[1]) { if (ret_len + freclen > len) return (-1); memcpy(packet + ret_len, ftoft_buf_1, freclen); @@ -879,7 +1262,7 @@ } static int -nf_options_to_flowset(u_char *packet, u_int len, const struct timeval *system_boot_time, u_int *len_used) +nf_sampling_option_to_flowset(u_char *packet, u_int len, const struct timeval *system_boot_time, u_int *len_used) { u_int freclen, ret_len, nflows; u_int32_t rec32; @@ -889,6 +1272,24 @@ bzero(ftoft_buf_0, sizeof(ftoft_buf_0)); *len_used = nflows = ret_len = 0; + /* NF9_OPT_SCOPE_SYSTEM */ + switch (config.nfprobe_source_ha.family) { + case AF_INET: + memcpy(ftoft_ptr_0, &config.nfprobe_source_ha.address.ipv4, 4); + ftoft_ptr_0 += 4; + break; +#if defined ENABLE_IPV6 + case AF_INET6: + memcpy(ftoft_ptr_0, &config.nfprobe_source_ha.address.ipv6, 16); + ftoft_ptr_0 += 16; + break; +#endif + default: + memset(ftoft_ptr_0, 0, 4); + ftoft_ptr_0 += 4; + break; + } + rec8 = 1; /* NF9_FLOW_SAMPLER_ID */ memcpy(ftoft_ptr_0, &rec8, 1); ftoft_ptr_0 += 1; @@ -904,7 +1305,7 @@ memcpy(ftoft_ptr_0, &rec32, 4); ftoft_ptr_0 += 4; - freclen = options_int_template.tot_rec_len; + freclen = sampling_option_int_template.tot_rec_len; if (ret_len + freclen > len) return (-1); @@ -917,6 +1318,55 @@ return (nflows); } +static int +nf_class_option_to_flowset(u_int idx, u_char *packet, u_int len, const struct timeval *system_boot_time, u_int *len_used) +{ + u_int freclen, ret_len, nflows; + char *ftoft_ptr_0 = ftoft_buf_0; + + bzero(ftoft_buf_0, sizeof(ftoft_buf_0)); + *len_used = nflows = ret_len = 0; + + /* NF9_OPT_SCOPE_SYSTEM */ + switch (config.nfprobe_source_ha.family) { + case AF_INET: + memcpy(ftoft_ptr_0, &config.nfprobe_source_ha.address.ipv4, 4); + ftoft_ptr_0 += 4; + break; +#if defined ENABLE_IPV6 + case AF_INET6: + memcpy(ftoft_ptr_0, &config.nfprobe_source_ha.address.ipv6, 16); + ftoft_ptr_0 += 16; + break; +#endif + default: + memset(ftoft_ptr_0, 0, 4); + ftoft_ptr_0 += 4; + break; + } + + /* NF9_FLOW_APPLICATION_ID */ + memcpy(ftoft_ptr_0, &class[idx].id, 4); + ftoft_ptr_0 += 4; + + /* NF9_FLOW_APPLICATION_NAME */ + strlcpy(ftoft_ptr_0, class[idx].protocol, 16); + ftoft_ptr_0 += 16; + + freclen = class_option_int_template.tot_rec_len; + + if (ret_len + freclen > len) + return (-1); + + memcpy(packet + ret_len, ftoft_buf_0, freclen); + + ret_len += freclen; + nflows++; + + *len_used = ret_len; + return (nflows); +} + /* * Given an array of expired flows, send netflow v9 report packets * Returns number of packets sent or -1 on error @@ -929,9 +1379,11 @@ struct NF9_HEADER *nf9; struct NF9_DATA_FLOWSET_HEADER *dh; struct timeval now; - u_int offset, last_af, j, num_packets, inc, last_valid; + u_int offset, last_af, flow_j, num_packets, inc, last_valid; + u_int num_class, class_j; + int direction, new_direction; socklen_t errsz; - int err, r, i; + int err, r, flow_i, class_i; u_char packet[NF9_SOFTFLOWD_MAX_PACKET_SIZE]; u_int8_t *sid_ptr; @@ -943,8 +1395,13 @@ nf9_pkts_until_template = 0; } - last_valid = num_packets = 0; - for (j = 0; j < num_flows;) { + num_packets = 0; + num_class = pmct_find_first_free(); + + for (direction = DIRECTION_IN; direction <= DIRECTION_OUT; direction++) { + last_valid = 0; new_direction = TRUE; + + for (flow_j = 0, class_j = 0; flow_j < num_flows;) { bzero(packet, sizeof(packet)); nf9 = (struct NF9_HEADER *)packet; @@ -952,7 +1409,6 @@ nf9->flows = 0; /* Filled as we go, htons at end */ nf9->uptime_ms = htonl(timeval_sub_ms(&now, system_boot_time)); nf9->time_sec = htonl(time(NULL)); - // nf9->package_sequence = htonl(*flows_exported + j); nf9->package_sequence = htonl(++(*flows_exported)); nf9->source_id = 0; @@ -967,22 +1423,38 @@ memcpy(packet + offset, &v4_template, v4_template.tot_len); offset += v4_template.tot_len; nf9->flows++; + memcpy(packet + offset, &v4_template_out, v4_template_out.tot_len); + offset += v4_template_out.tot_len; + nf9->flows++; memcpy(packet + offset, &v6_template, v6_template.tot_len); offset += v6_template.tot_len; nf9->flows++; + memcpy(packet + offset, &v6_template_out, v6_template_out.tot_len); + offset += v6_template_out.tot_len; + nf9->flows++; if (config.sampling_rate || config.ext_sampling_rate) { - memcpy(packet + offset, &options_template, options_template.tot_len); - offset += options_template.tot_len; + memcpy(packet + offset, &sampling_option_template, sampling_option_template.tot_len); + offset += sampling_option_template.tot_len; nf9->flows++; send_options = TRUE; + send_sampling_option = TRUE; + } + if (config.nfprobe_what_to_count & COUNT_CLASS) { + memcpy(packet + offset, &class_option_template, class_option_template.tot_len); + offset += class_option_template.tot_len; + nf9->flows++; + send_options = TRUE; + send_class_option = TRUE; } nf9_pkts_until_template = NF9_DEFAULT_TEMPLATE_INTERVAL; } dh = NULL; last_af = 0; - for (i = 0; i + j < num_flows; i++) { - if (dh == NULL || flows[i + j]->af != last_af) { + for (flow_i = 0, class_i = 0; flow_i + flow_j < num_flows; flow_i++) { + /* Shall we send a new flowset header? */ + if (dh == NULL || (!send_options && (flows[flow_i + flow_j]->af != last_af || new_direction)) || + send_sampling_option || (send_class_option && !class_i) ) { if (dh != NULL) { if (offset % 4 != 0) { /* Pad to multiple of 4 */ @@ -1000,48 +1472,80 @@ dh = (struct NF9_DATA_FLOWSET_HEADER *) (packet + offset); if (send_options) { - dh->c.flowset_id = options_template.h.template_id; - last_af = 0; + if (send_sampling_option) { + dh->c.flowset_id = sampling_option_template.h.template_id; + // last_af = 0; new_direction = TRUE; + } + else if (send_class_option) { + dh->c.flowset_id = class_option_template.h.template_id; + // last_af = 0; new_direction = TRUE; + } } else { - dh->c.flowset_id = - (flows[i + j]->af == AF_INET) ? - v4_template.h.template_id : - v6_template.h.template_id; - last_af = flows[i + j]->af; + if (flows[flow_i + flow_j]->af == AF_INET) { + if (direction == DIRECTION_IN) + dh->c.flowset_id = v4_template.h.template_id; + else if (direction == DIRECTION_OUT) + dh->c.flowset_id = v4_template_out.h.template_id; + } + else if (flows[flow_i + flow_j]->af == AF_INET6) { + if (direction == DIRECTION_IN) + dh->c.flowset_id = v6_template.h.template_id; + else if (direction == DIRECTION_OUT) + dh->c.flowset_id = v6_template_out.h.template_id; + } + // last_af = flows[flow_i + flow_j]->af; /* XXX */ } last_valid = offset; + new_direction = FALSE; dh->c.length = sizeof(*dh); /* Filled as we go */ offset += sizeof(*dh); } - if (send_options) - r = nf_options_to_flowset(packet + offset, - sizeof(packet) - offset, system_boot_time, &inc); + /* Send flowset data over */ + if (send_options) { + if (send_sampling_option) { + r = nf_sampling_option_to_flowset(packet + offset, + sizeof(packet) - offset, system_boot_time, &inc); + send_sampling_option = FALSE; + } + else if (send_class_option) { + r = nf_class_option_to_flowset(class_i + class_j, packet + offset, + sizeof(packet) - offset, system_boot_time, &inc); + + if (r > 0) class_i += r; + if (class_i + class_j >= num_class) send_class_option = FALSE; + } + } else - r = nf_flow_to_flowset(flows[i + j], packet + offset, - sizeof(packet) - offset, system_boot_time, &inc); + r = nf_flow_to_flowset(flows[flow_i + flow_j], packet + offset, + sizeof(packet) - offset, system_boot_time, &inc, direction); + + /* Wrap up */ if (r <= 0) { /* yank off data header, if we had to go back */ if (last_valid) - offset = last_valid; - break; + offset = last_valid; + if (r < 0) break; } - offset += inc; - dh->c.length += inc; - nf9->flows += r; - last_valid = 0; /* Don't clobber this header now */ - if (verbose_flag) { - Log(LOG_DEBUG, "Flow %d/%d: " - "r %d offset %d type %04x len %d(0x%04x) " - "flows %d\n", r, i, j, offset, - dh->c.flowset_id, dh->c.length, - dh->c.length, nf9->flows); - } - - if (send_options) { - send_options = FALSE; - i--; + else { + offset += inc; + dh->c.length += inc; + nf9->flows += r; + last_valid = 0; /* Don't clobber this header now */ + if (verbose_flag) { + Log(LOG_DEBUG, "DEBUG ( %s/%s ): Building NetFlow v9 packet: offset = %d, template ID = %d, total len = %d, # elements = %d\n", + config.name, config.type, offset, ntohs(dh->c.flowset_id), dh->c.length, nf9->flows); + } + + if (send_options) { + if (!send_sampling_option && + !send_class_option) { + send_options = FALSE; + } + flow_i--; + } + else last_af = flows[flow_i + flow_j]->af; /* XXX */ } } /* Don't finish header if it has already been done */ @@ -1054,21 +1558,25 @@ /* Finalise last header */ dh->c.length = htons(dh->c.length); } - nf9->flows = htons(nf9->flows); + if (nf9->flows > 0) { + nf9->flows = htons(nf9->flows); - if (verbose_flag) - Log(LOG_DEBUG, "Sending flow packet len = %d\n", offset); - errsz = sizeof(err); - /* Clear ICMP errors */ - getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); - if (send(nfsock, packet, (size_t)offset, 0) == -1) + if (verbose_flag) + Log(LOG_DEBUG, "DEBUG ( %s/%s ): Sending NetFlow v9 packet: len = %d\n", config.name, config.type, offset); + errsz = sizeof(err); + /* Clear ICMP errors */ + getsockopt(nfsock, SOL_SOCKET, SO_ERROR, &err, &errsz); + if (send(nfsock, packet, (size_t)offset, 0) == -1) return (-1); - num_packets++; - nf9_pkts_until_template--; + num_packets++; + nf9_pkts_until_template--; + } + else --(*flows_exported); - j += i; + class_j += class_i; + flow_j += flow_i; + } } - // *flows_exported += j; return (num_packets); } diff -Nru pmacct-0.12.1/src/nfprobe_plugin/nfprobe_plugin.c pmacct-0.12.5/src/nfprobe_plugin/nfprobe_plugin.c --- pmacct-0.12.1/src/nfprobe_plugin/nfprobe_plugin.c 2010-03-12 00:09:17.000000000 +0000 +++ pmacct-0.12.5/src/nfprobe_plugin/nfprobe_plugin.c 2010-10-26 17:06:40.000000000 +0000 @@ -171,25 +171,6 @@ EXPIRY_PROTOTYPE(EXPIRIES, EXPIRY, trp, expiry_compare); EXPIRY_GENERATE(EXPIRIES, EXPIRY, trp, expiry_compare); -#if 0 -/* Dump a packet */ -static void -dump_packet(const u_int8_t *p, int len) -{ - char buf[1024], tmp[3]; - int i; - - for (*buf = '\0', i = 0; i < len; i++) { - snprintf(tmp, sizeof(tmp), "%02x%s", p[i], i % 2 ? " " : ""); - if (strlcat(buf, tmp, sizeof(buf) - 4) >= sizeof(buf) - 4) { - strlcat(buf, "...", sizeof(buf)); - break; - } - } - Log(LOG_INFO, "packet len %d: %s\n", len, buf); -} -#endif - /* Format a time in an ISOish format */ static const char * format_time(time_t t) @@ -302,6 +283,33 @@ l2_to_flowrec(struct FLOW *flow, struct pkt_data *data, struct pkt_extras *extras, int ndx) { struct pkt_primitives *p = &data->primitives; + int direction = 0; + + if (config.nfprobe_direction) { + switch (config.nfprobe_direction) { + case DIRECTION_IN: + case DIRECTION_OUT: + direction = config.nfprobe_direction; + break; + case DIRECTION_TAG: + if (p->id == 1) direction = DIRECTION_IN; + else if (p->id == 2) direction = DIRECTION_OUT; + break; + case DIRECTION_TAG2: + if (p->id2 == 1) direction = DIRECTION_IN; + else if (p->id2 == 2) direction = DIRECTION_OUT; + break; + } + + if (direction == DIRECTION_IN) { + flow->direction[ndx] = DIRECTION_IN; + flow->direction[ndx ^ 1] = 0; + } + else if (direction == DIRECTION_OUT) { + flow->direction[ndx] = DIRECTION_OUT; + flow->direction[ndx ^ 1] = 0; + } + } #if defined HAVE_L2 memcpy(&flow->mac[ndx][0], &p->eth_shost, 6); @@ -310,13 +318,63 @@ flow->mpls_label[ndx] = extras->mpls_top_label; #endif - flow->ifindex[ndx] = p->ifindex_in; - flow->ifindex[ndx ^ 1] = p->ifindex_out; + if (!p->ifindex_in && !p->ifindex_out) { + if (config.nfprobe_ifindex_type) { + switch (config.nfprobe_ifindex_type) { + case IFINDEX_STATIC: + flow->ifindex[ndx] = (direction == DIRECTION_IN) ? config.nfprobe_ifindex : 0; + flow->ifindex[ndx ^ 1] = (direction == DIRECTION_OUT) ? config.nfprobe_ifindex : 0; + break; + case IFINDEX_TAG: + flow->ifindex[ndx] = (direction == DIRECTION_IN) ? p->id : 0; + flow->ifindex[ndx ^ 1] = (direction == DIRECTION_OUT) ? p->id : 0; + break; + case IFINDEX_TAG2: + flow->ifindex[ndx] = (direction == DIRECTION_IN) ? p->id2 : 0; + flow->ifindex[ndx ^ 1] = (direction == DIRECTION_OUT) ? p->id2 : 0; + break; + default: + flow->ifindex[ndx] = 0; + flow->ifindex[ndx ^ 1] = 0; + } + } + } + else { + flow->ifindex[ndx] = p->ifindex_in; + flow->ifindex[ndx ^ 1] = p->ifindex_out; + } return (0); } static int +l2_to_flowrec_update(struct FLOW *flow, struct pkt_data *data, struct pkt_extras *extras, int ndx) +{ + struct pkt_primitives *p = &data->primitives; + int direction = 0; + + if (config.nfprobe_direction) { + switch (config.nfprobe_direction) { + case DIRECTION_TAG: + if (p->id == 1) direction = DIRECTION_IN; + else if (p->id == 2) direction = DIRECTION_OUT; + break; + case DIRECTION_TAG2: + if (p->id2 == 1) direction = DIRECTION_IN; + else if (p->id2 == 2) direction = DIRECTION_OUT; + break; + } + + if (direction == DIRECTION_IN) { + if (!flow->direction[ndx]) flow->direction[ndx] = DIRECTION_IN; + } + else if (direction == DIRECTION_OUT) { + if (!flow->direction[ndx]) flow->direction[ndx] = DIRECTION_OUT; + } + } +} + +static int ASN_to_flowrec(struct FLOW *flow, struct pkt_data *data, int ndx) { struct pkt_primitives *p = &data->primitives; @@ -340,6 +398,7 @@ flow->af = af; flow->addr[ndx].v4 = p->src_ip.address.ipv4; flow->addr[ndx ^ 1].v4 = p->dst_ip.address.ipv4; + flow->bgp_next_hop[ndx].v4 = extras->bgp_next_hop.address.ipv4; flow->mask[ndx] = p->src_nmask; flow->mask[ndx ^ 1] = p->dst_nmask; flow->tos[ndx] = p->tos; @@ -361,6 +420,20 @@ // return (0); } +static int +ipv4_to_flowrec_update(struct FLOW *flow, struct pkt_data *data, struct pkt_extras *extras, int *isfrag, int af) +{ + struct pkt_primitives *p = &data->primitives; + int ndx; + + /* Prepare to store flow in canonical format */ + ndx = memcmp(&p->src_ip.address.ipv4, &p->dst_ip.address.ipv4, sizeof(p->src_ip.address.ipv4)) > 0 ? 1 : 0; + + if (!flow->bgp_next_hop[ndx].v4.s_addr) flow->bgp_next_hop[ndx].v4 = extras->bgp_next_hop.address.ipv4; + + l2_to_flowrec_update(flow, data, extras, ndx); +} + #if defined ENABLE_IPV6 /* Convert a IPv6 packet to a partial flow record (used for comparison) */ static int @@ -377,6 +450,7 @@ flow->ip6_flowlabel[ndx] = 0; flow->addr[ndx].v6 = p->src_ip.address.ipv6; flow->addr[ndx ^ 1].v6 = p->dst_ip.address.ipv6; + flow->bgp_next_hop[ndx].v6 = extras->bgp_next_hop.address.ipv6; flow->mask[ndx] = p->src_nmask; flow->mask[ndx ^ 1] = p->dst_nmask; flow->octets[ndx] = data->pkt_len; @@ -395,6 +469,23 @@ // return (0); } + +static int +ipv6_to_flowrec_update(struct FLOW *flow, struct pkt_data *data, struct pkt_extras *extras, int *isfrag, int af) +{ + struct pkt_primitives *p = &data->primitives; + struct in6_addr dummy_ipv6; + int ndx; + + /* Prepare to store flow in canonical format */ + memset(&dummy_ipv6, 0, sizeof(dummy_ipv6)); + ndx = memcmp(&p->src_ip.address.ipv6, &p->dst_ip.address.ipv6, sizeof(p->src_ip.address.ipv6)) > 0 ? 1 : 0; + + if (!memcmp(&dummy_ipv6, &flow->bgp_next_hop[ndx].v6, sizeof(dummy_ipv6))) + flow->bgp_next_hop[ndx].v6 = extras->bgp_next_hop.address.ipv6; + + l2_to_flowrec_update(flow, data, extras, ndx); +} #endif static void @@ -561,6 +652,17 @@ flow->flows[1] += tmp.flows[1]; flow->tcp_flags[1] |= tmp.tcp_flags[1]; flow->tos[1] = tmp.tos[1]; // XXX + /* Address family dependent items to update */ + switch (flow->af) { + case AF_INET: + ipv4_to_flowrec_update(flow, data, extras, &frag, af); + break; +#if defined ENABLE_IPV6 + case AF_INET6: + ipv6_to_flowrec_update(flow, data, extras, &frag, af); + break; +#endif + } if (!flow->class) flow->class = tmp.class; if (!flow->tag[0]) flow->tag[0] = tmp.tag[0]; if (!flow->tag[1]) flow->tag[1] = tmp.tag[1]; @@ -892,97 +994,6 @@ } /* - * Log our current status. - * Includes summary counters and (in verbose mode) the list of current flows - * and the tree of expiry events. - */ -static int -statistics(struct FLOWTRACK *ft, FILE *out) -{ - int i; - struct protoent *pe; - char proto[32]; - - fprintf(out, "Number of active flows: %d\n", ft->num_flows); - fprintf(out, "Packets processed: %llu\n", ft->total_packets); - fprintf(out, "Fragments: %llu\n", ft->frag_packets); - fprintf(out, "Ignored packets: %llu (%llu non-IP, %llu too short)\n", - ft->non_ip_packets + ft->bad_packets, ft->non_ip_packets, ft->bad_packets); - fprintf(out, "Flows expired: %llu (%llu forced)\n", - ft->flows_expired, ft->flows_force_expired); - fprintf(out, "Flows exported: %llu in %llu packets (%llu failures)\n", - ft->flows_exported, ft->packets_sent, ft->flows_dropped); - - fprintf(out, "\n"); - - if (ft->flows_expired != 0) { - fprintf(out, "Expired flow statistics: minimum average maximum\n"); - fprintf(out, " Flow bytes: %12.0f %12.0f %12.0f\n", - ft->octets.min, ft->octets.mean, ft->octets.max); - fprintf(out, " Flow packets: %12.0f %12.0f %12.0f\n", - ft->packets.min, ft->packets.mean, ft->packets.max); - fprintf(out, " Duration: %12.2fs %12.2fs %12.2fs\n", - ft->duration.min, ft->duration.mean, ft->duration.max); - - fprintf(out, "\n"); - fprintf(out, "Expired flow reasons:\n"); - fprintf(out, " tcp = %9llu tcp.rst = %9llu tcp.fin = %9llu\n", - ft->expired_tcp, ft->expired_tcp_rst, ft->expired_tcp_fin); - fprintf(out, " udp = %9llu icmp = %9llu general = %9llu\n", - ft->expired_udp, ft->expired_icmp, ft->expired_general); - fprintf(out, " maxlife = %9llu\n", ft->expired_maxlife); - fprintf(out, " over 2Gb = %9llu\n", ft->expired_overbytes); - fprintf(out, " maxflows = %9llu\n", ft->expired_maxflows); - fprintf(out, " flushed = %9llu\n", ft->expired_flush); - - fprintf(out, "\n"); - - fprintf(out, "Per-protocol statistics: Octets Packets Avg Life Max Life\n"); - for(i = 0; i < 256; i++) { - if (ft->packets_pp[i]) { - pe = getprotobynumber(i); - snprintf(proto, sizeof(proto), "%s (%d)", - pe != NULL ? pe->p_name : "Unknown", i); - fprintf(out, - " %17s: %14llu %12llu %8.2fs %10.2fs\n", - proto, - ft->octets_pp[i], - ft->packets_pp[i], - ft->duration_pp[i].mean, - ft->duration_pp[i].max); - } - } - } - - return (0); -} - -static void -dump_flows(struct FLOWTRACK *ft, FILE *out) -{ - struct EXPIRY *expiry; - time_t now; - - now = time(NULL); - - EXPIRY_FOREACH(expiry, EXPIRIES, &ft->expiries) { - fprintf(out, "ACTIVE %s\n", format_flow(expiry->flow)); - if ((long int) expiry->expires_at - now < 0) { - fprintf(out, - "EXPIRY EVENT for flow %llu now%s\n", - expiry->flow->flow_seq, - expiry->expires_at == 0 ? " (FORCED)": ""); - } else { - fprintf(out, - "EXPIRY EVENT for flow %llu in %ld seconds\n", - expiry->flow->flow_seq, - (long int) expiry->expires_at - now); - } - fprintf(out, "\n"); - } -} - -/* * Per-packet callback function from libpcap. Pass the packet (if it is IP) * sans datalink headers to process_packet. */ @@ -1013,69 +1024,79 @@ static int connsock(struct sockaddr_storage *addr, socklen_t len, int hoplimit) { - int s, ret = 0; - unsigned int h6; - unsigned char h4; - struct sockaddr_in *in4 = (struct sockaddr_in *)addr; - struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; - struct host_addr source_ip; - struct sockaddr ssource_ip; - - if (config.nfprobe_source_ip) { - ret = str_to_addr(config.nfprobe_source_ip, &source_ip); - addr_to_sa(&ssource_ip, &source_ip, 0); - } + int s, ret = 0; + unsigned int h6; + unsigned char h4; + struct sockaddr_in *in4 = (struct sockaddr_in *)addr; +#if defined ENABLE_IPV6 + struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; +#endif + struct sockaddr ssource_ip; - if ((s = socket(addr->ss_family, SOCK_DGRAM, 0)) == -1) { - fprintf(stderr, "socket() error: %s\n", - strerror(errno)); - exit_plugin(1); - } + if (config.nfprobe_source_ip) { + ret = str_to_addr(config.nfprobe_source_ip, &config.nfprobe_source_ha); + addr_to_sa(&ssource_ip, &config.nfprobe_source_ha, 0); + } - if (ret && bind(s, (struct sockaddr *) &ssource_ip, sizeof(ssource_ip)) == -1) { - fprintf(stderr, "bind() error: %s\n", - strerror(errno)); - } + if ((s = socket(addr->ss_family, SOCK_DGRAM, 0)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): socket() failed: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } - if (connect(s, (struct sockaddr*)addr, len) == -1) { - fprintf(stderr, "connect() error: %s\n", - strerror(errno)); - exit_plugin(1); - } - - switch (addr->ss_family) { - case AF_INET: - /* Default to link-local TTL for multicast addresses */ - if (hoplimit == -1 && IN_MULTICAST(in4->sin_addr.s_addr)) - hoplimit = 1; - if (hoplimit == -1) - break; - h4 = hoplimit; - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, - &h4, sizeof(h4)) == -1) { - fprintf(stderr, "setsockopt(IP_MULTICAST_TTL, " - "%u): %s\n", h4, strerror(errno)); - exit_plugin(1); - } - break; + if (config.nfprobe_ipprec) { + int opt = config.nfprobe_ipprec << 5; + int rc; + + rc = setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); + if (rc < 0) Log(LOG_WARNING, "WARN ( %s/%s ): setsockopt() failed for IP_TOS: %s\n", config.name, config.type, strerror(errno)); + } + + if (config.pipe_size) { + int rc; + + rc = Setsocksize(s, SOL_SOCKET, SO_SNDBUF, &config.pipe_size, sizeof(config.pipe_size)); + if (rc < 0) Log(LOG_WARNING, "WARN ( %s/%s ): setsockopt() failed for SOL_SNDBUF: %s\n", config.name, config.type, strerror(errno)); + } + + if (ret && bind(s, (struct sockaddr *) &ssource_ip, sizeof(ssource_ip)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): bind() failed: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + + if (connect(s, (struct sockaddr*)addr, len) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): connect() failed: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + + switch (addr->ss_family) { + case AF_INET: + /* Default to link-local TTL for multicast addresses */ + if (hoplimit == -1 && IN_MULTICAST(in4->sin_addr.s_addr)) + hoplimit = 1; + if (hoplimit == -1) + break; + h4 = hoplimit; + if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &h4, sizeof(h4)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): setsockopt() failed for IP_MULTICAST_TTL: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + break; #if defined ENABLE_IPV6 - case AF_INET6: - /* Default to link-local hoplimit for multicast addresses */ - if (hoplimit == -1 && IN6_IS_ADDR_MULTICAST(&in6->sin6_addr)) - hoplimit = 1; - if (hoplimit == -1) - break; - h6 = hoplimit; - if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, - &h6, sizeof(h6)) == -1) { - fprintf(stderr, "setsockopt(IPV6_MULTICAST_HOPS, %u): " - "%s\n", h6, strerror(errno)); - exit_plugin(1); - } + case AF_INET6: + /* Default to link-local hoplimit for multicast addresses */ + if (hoplimit == -1 && IN6_IS_ADDR_MULTICAST(&in6->sin6_addr)) + hoplimit = 1; + if (hoplimit == -1) + break; + h6 = hoplimit; + if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &h6, sizeof(h6)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): setsockopt() failed for IPV6_MULTICAST_HOPS: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } #endif - } + } - return(s); + return(s); } static void @@ -1164,49 +1185,51 @@ static void parse_hostport(const char *s, struct sockaddr *addr, socklen_t *len) { - char *orig, *host, *port; - struct addrinfo hints, *res; - int herr; - - if ((host = orig = strdup(s)) == NULL) { - fprintf(stderr, "Out of memory\n"); - exit_plugin(1); - } + char *orig, *host, *port; + struct addrinfo hints, *res; + int herr; + + if ((host = orig = strdup(s)) == NULL) { + Log(LOG_ERR, "ERROR ( %s/%s ): parse_hostport(), strdup() out of memory\n", config.name, config.type); + exit_plugin(1); + } - trim_spaces(host); - trim_spaces(orig); + trim_spaces(host); + trim_spaces(orig); - if ((port = strrchr(host, ':')) == NULL || - *(++port) == '\0' || *host == '\0') { - fprintf(stderr, "Invalid -n argument.\n"); - exit_plugin(1); - } - *(port - 1) = '\0'; + if ((port = strrchr(host, ':')) == NULL || *(++port) == '\0' || *host == '\0') { + Log(LOG_ERR, "ERROR ( %s/%s ): parse_hostport(), invalid 'nfprobe_receiver' argument\n", config.name, config.type); + exit_plugin(1); + } + *(port - 1) = '\0'; - /* Accept [host]:port for numeric IPv6 addresses */ - if (*host == '[' && *(port - 2) == ']') { - host++; - *(port - 2) = '\0'; - } + /* Accept [host]:port for numeric IPv6 addresses */ + if (*host == '[' && *(port - 2) == ']') { + host++; + *(port - 2) = '\0'; + } - memset(&hints, '\0', sizeof(hints)); - hints.ai_socktype = SOCK_DGRAM; - if ((herr = getaddrinfo(host, port, &hints, &res)) == -1) { - fprintf(stderr, "Address lookup failed: %s\n", - gai_strerror(herr)); - exit_plugin(1); - } - if (res == NULL || res->ai_addr == NULL) { - fprintf(stderr, "No addresses found for [%s]:%s\n", host, port); - exit_plugin(1); - } - if (res->ai_addrlen > *len) { - Log(LOG_ERR, "ERROR ( %s/%s ): Address too long.\n", config.name, config.type); - exit_plugin(1); - } - memcpy(addr, res->ai_addr, res->ai_addrlen); - free(orig); - *len = res->ai_addrlen; + memset(&hints, '\0', sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + + if ((herr = getaddrinfo(host, port, &hints, &res)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): parse_hostport(), address lookup failed\n", config.name, config.type); + exit_plugin(1); + } + + if (res == NULL || res->ai_addr == NULL) { + Log(LOG_ERR, "ERROR ( %s/%s ): parse_hostport(), no addresses found for [%s]:%s\n", config.name, config.type, host, port); + exit_plugin(1); + } + + if (res->ai_addrlen > *len) { + Log(LOG_ERR, "ERROR ( %s/%s ): parse_hostport(), address too long.\n", config.name, config.type); + exit_plugin(1); + } + + memcpy(addr, res->ai_addr, res->ai_addrlen); + free(orig); + *len = res->ai_addrlen; } static void @@ -1265,7 +1288,7 @@ recollect_pipe_memory(ptr); pm_setproctitle("%s [%s]", "Netflow Probe Plugin", config.name); if (config.pidfile) write_pid_file_plugin(config.pidfile, config.type, config.name); - Log(LOG_INFO, "INFO ( %s/%s ): NetFlow probe plugin is based on softflowd 0.9.7 software, Copyright 2002 Damien Miller All rights reserved.\n", + Log(LOG_INFO, "INFO ( %s/%s ): NetFlow probe plugin is originally based on softflowd 0.9.7 software, Copyright 2002 Damien Miller All rights reserved.\n", config.name, config.type); reload_map = FALSE; diff -Nru pmacct-0.12.1/src/nfprobe_plugin/nfprobe_plugin.h pmacct-0.12.5/src/nfprobe_plugin/nfprobe_plugin.h --- pmacct-0.12.1/src/nfprobe_plugin/nfprobe_plugin.h 2010-03-06 12:10:17.000000000 +0000 +++ pmacct-0.12.5/src/nfprobe_plugin/nfprobe_plugin.h 2010-09-09 14:35:48.000000000 +0000 @@ -141,6 +141,7 @@ /* Flow identity (all are in network byte order) */ int af; /* Address family of flow */ + u_int8_t direction[2]; /* Flow direction */ u_int32_t ip6_flowlabel[2]; /* IPv6 Flowlabel */ union { struct in_addr v4; @@ -152,8 +153,12 @@ u_int8_t protocol; /* Protocol */ u_int8_t tos[2]; /* ToS/DSCP */ - /* ASN stuff */ + /* ASN/BGP stuff */ as_t as[2]; /* Autonomous System numbers */ + union { + struct in_addr v4; + struct in6_addr v6; + } bgp_next_hop[2]; /* L2 stuff */ u_int8_t mac[2][6]; /* Endpoint L2/Ethernet MAC addresses */ diff -Nru pmacct-0.12.1/src/nfv9_template.c pmacct-0.12.5/src/nfv9_template.c --- pmacct-0.12.1/src/nfv9_template.c 2009-10-03 21:14:36.000000000 +0000 +++ pmacct-0.12.5/src/nfv9_template.c 2010-10-31 22:51:41.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -88,15 +88,41 @@ ptr->template_type = 0; ptr->num = num; + log_template_v9_header(ptr, pptrs); + count = num; tpl = (u_char *) hdr; tpl += NfTplHdrV9Sz; field = (struct template_field_v9 *)tpl; while (count) { type = ntohs(field->type); - ptr->tpl[type].off = ptr->len; - ptr->tpl[type].len = ntohs(field->len); - ptr->len += ptr->tpl[type].len; + log_template_v9_field(type, ptr->len, ntohs(field->len)); + + /* Cisco ASA hack */ + switch (type) { + case NF9_ASA_XLATE_IPV4_SRC_ADDR: + type = NF9_XLATE_IPV4_SRC_ADDR; + break; + case NF9_ASA_XLATE_IPV4_DST_ADDR: + type = NF9_XLATE_IPV4_DST_ADDR; + break; + case NF9_ASA_XLATE_L4_SRC_PORT: + type = NF9_XLATE_L4_SRC_PORT; + break; + case NF9_ASA_XLATE_L4_DST_PORT: + type = NF9_XLATE_L4_DST_PORT; + break; + default: + break; + } + + if (type < NF9_MAX_DEFINED_FIELD) { + ptr->tpl[type].off = ptr->len; + ptr->tpl[type].len = ntohs(field->len); + ptr->len += ptr->tpl[type].len; + } + else ptr->len += ntohs(field->len); + count--; field++; } @@ -104,6 +130,8 @@ if (prevptr) prevptr->next = ptr; else tpl_cache.c[modulo] = ptr; + log_template_v9_footer(ptr->len); + return ptr; } @@ -123,18 +151,85 @@ tpl->num = num; tpl->next = next; + log_template_v9_header(tpl, pptrs); + count = num; ptr = (u_char *) hdr; ptr += NfTplHdrV9Sz; field = (struct template_field_v9 *)ptr; while (count) { type = ntohs(field->type); - tpl->tpl[type].off = tpl->len; - tpl->tpl[type].len = ntohs(field->len); - tpl->len += tpl->tpl[type].len; + log_template_v9_field(type, tpl->len, ntohs(field->len)); + + /* Cisco ASA hack */ + switch (type) { + case NF9_ASA_XLATE_IPV4_SRC_ADDR: + type = NF9_XLATE_IPV4_SRC_ADDR; + break; + case NF9_ASA_XLATE_IPV4_DST_ADDR: + type = NF9_XLATE_IPV4_DST_ADDR; + break; + case NF9_ASA_XLATE_L4_SRC_PORT: + type = NF9_XLATE_L4_SRC_PORT; + break; + case NF9_ASA_XLATE_L4_DST_PORT: + type = NF9_XLATE_L4_DST_PORT; + break; + default: + break; + } + + if (type < NF9_MAX_DEFINED_FIELD) { + tpl->tpl[type].off = tpl->len; + tpl->tpl[type].len = ntohs(field->len); + tpl->len += tpl->tpl[type].len; + } + else tpl->len += ntohs(field->len); + count--; field++; } + + log_template_v9_footer(tpl->len); +} + +void log_template_v9_header(struct template_cache_entry *tpl, struct packet_ptrs *pptrs) +{ + struct host_addr a; + u_char agent_addr[50]; + u_int16_t agent_port, count, size; + + sa_to_addr((struct sockaddr *)pptrs->f_agent, &a, &agent_port); + addr_to_str(agent_addr, &a); + + Log(LOG_DEBUG, "DEBUG ( default/core ): NfV9 agent : %s:%u\n", agent_addr, ntohl(((struct struct_header_v9 *)pptrs->f_header)->source_id)); + Log(LOG_DEBUG, "DEBUG ( default/core ): NfV9 template type : %s\n", ( tpl->template_type == 0 ) ? "flow" : "options"); + Log(LOG_DEBUG, "DEBUG ( default/core ): NfV9 template ID : %u\n", ntohs(tpl->template_id)); + Log(LOG_DEBUG, "DEBUG ( default/core ): ----------------------------------------\n"); + Log(LOG_DEBUG, "DEBUG ( default/core ): | field type | offset | size |\n"); +} + +void log_template_v9_field(u_int16_t type, u_int16_t off, u_int16_t len) +{ + if (type <= MAX_TPL_DESC_LIST && strlen(tpl_desc_list[type])) + Log(LOG_DEBUG, "DEBUG ( default/core ): | %-18s | %6u | %6u |\n", tpl_desc_list[type], off, len); + else + Log(LOG_DEBUG, "DEBUG ( default/core ): | %-18u | %6u | %6u |\n", type, off, len); +} + +void log_opt_template_v9_field(u_int16_t type, u_int16_t off, u_int16_t len) +{ + if (type <= MAX_OPT_TPL_DESC_LIST && strlen(opt_tpl_desc_list[type])) + Log(LOG_DEBUG, "DEBUG ( default/core ): | %-18s | %6u | %6u |\n", opt_tpl_desc_list[type], off, len); + else + Log(LOG_DEBUG, "DEBUG ( default/core ): | %-18u | %6u | %6u |\n", type, off, len); +} + +void log_template_v9_footer(u_int16_t size) +{ + Log(LOG_DEBUG, "DEBUG ( default/core ): ----------------------------------------\n"); + Log(LOG_DEBUG, "DEBUG ( default/core ): NfV9 record size : %u\n", size); + Log(LOG_DEBUG, "DEBUG ( default/core ): \n"); } struct template_cache_entry *insert_opt_template_v9(struct options_template_hdr_v9 *hdr, struct packet_ptrs *pptrs) @@ -166,15 +261,22 @@ ptr->template_type = 1; ptr->num = (olen+slen)/sizeof(struct template_field_v9); + log_template_v9_header(ptr, pptrs); + count = ptr->num; tpl = (u_char *) hdr; tpl += NfOptTplHdrV9Sz; field = (struct template_field_v9 *)tpl; while (count) { type = ntohs(field->type); - ptr->tpl[type].off = ptr->len; - ptr->tpl[type].len = ntohs(field->len); - ptr->len += ptr->tpl[type].len; + log_opt_template_v9_field(type, ptr->len, ntohs(field->len)); + if (type < NF9_MAX_DEFINED_FIELD) { + ptr->tpl[type].off = ptr->len; + ptr->tpl[type].len = ntohs(field->len); + ptr->len += ptr->tpl[type].len; + } + else ptr->len += ntohs(field->len); + count--; field++; } @@ -182,6 +284,8 @@ if (prevptr) prevptr->next = ptr; else tpl_cache.c[modulo] = ptr; + log_template_v9_footer(ptr->len); + return ptr; } @@ -202,16 +306,25 @@ tpl->num = (olen+slen)/sizeof(struct template_field_v9); tpl->next = next; + log_template_v9_header(tpl, pptrs); + count = tpl->num; ptr = (u_char *) hdr; ptr += NfOptTplHdrV9Sz; field = (struct template_field_v9 *)ptr; while (count) { type = ntohs(field->type); - tpl->tpl[type].off = tpl->len; - tpl->tpl[type].len = ntohs(field->len); - tpl->len += tpl->tpl[type].len; + log_opt_template_v9_field(type, tpl->len, ntohs(field->len)); + if (type < NF9_MAX_DEFINED_FIELD) { + tpl->tpl[type].off = tpl->len; + tpl->tpl[type].len = ntohs(field->len); + tpl->len += tpl->tpl[type].len; + } + else tpl->len += ntohs(field->len); + count--; field++; } + + log_template_v9_footer(tpl->len); } diff -Nru pmacct-0.12.1/src/nl.c pmacct-0.12.5/src/nl.c --- pmacct-0.12.1/src/nl.c 2010-03-12 00:09:17.000000000 +0000 +++ pmacct-0.12.5/src/nl.c 2010-12-21 16:56:51.000000000 +0000 @@ -60,6 +60,7 @@ pptrs.bta_table = cb_data->bta_table; pptrs.ifindex_in = cb_data->ifindex_in; pptrs.ifindex_out = cb_data->ifindex_out; + pptrs.f_status = NULL; (*device->data->handler)(pkthdr, &pptrs); if (pptrs.iph_ptr) { diff -Nru pmacct-0.12.1/src/once.h pmacct-0.12.5/src/once.h --- pmacct-0.12.1/src/once.h 2009-10-17 19:55:31.000000000 +0000 +++ pmacct-0.12.5/src/once.h 2010-05-12 17:11:26.000000000 +0000 @@ -5,7 +5,7 @@ #endif EXT u_int32_t PdataSz, ChBufHdrSz, CharPtrSz, CounterSz, HostAddrSz; -EXT u_int32_t PpayloadSz, PextrasSz; +EXT u_int32_t PpayloadSz, PextrasSz, PmsgSz; EXT u_int32_t NfHdrV5Sz, NfHdrV1Sz, NfHdrV7Sz, NfHdrV8Sz, NfHdrV9Sz; EXT u_int32_t NfDataHdrV9Sz, NfTplHdrV9Sz, NfOptTplHdrV9Sz; EXT u_int32_t NfDataV1Sz, NfDataV5Sz, NfDataV7Sz; diff -Nru pmacct-0.12.1/src/pgsql_plugin.c pmacct-0.12.5/src/pgsql_plugin.c --- pmacct-0.12.1/src/pgsql_plugin.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/pgsql_plugin.c 2010-10-06 07:26:12.000000000 +0000 @@ -743,7 +743,8 @@ if (!db->fail) { PGret = PQexec(db->desc, buf); - if (PQresultStatus(PGret) != PGRES_COMMAND_OK) { + if ((PQresultStatus(PGret) != PGRES_COMMAND_OK) && + (PQresultStatus(PGret) != PGRES_TUPLES_OK)) { err_string = PQresultErrorMessage(PGret); Log(LOG_DEBUG, "DEBUG ( %s/%s ): FAILED query follows:\n%s\n", config.name, config.type, buf); Log(LOG_ERR, "ERROR ( %s/%s ): %s\n\n", config.name, config.type, err_string); @@ -807,6 +808,7 @@ if (typed) { if (config.sql_table_version == (SQL_TABLE_VERSION_BGP+1)) config.sql_table = pgsql_table_bgp; + else if (config.sql_table_version == 8) config.sql_table = pgsql_table_v8; else if (config.sql_table_version == 7) config.sql_table = pgsql_table_v7; else if (config.sql_table_version == 6) config.sql_table = pgsql_table_v6; else if (config.sql_table_version == 5) { @@ -831,6 +833,10 @@ } } else { + if (config.sql_table_version == 8) { + Log(LOG_WARNING, "WARN ( %s/%s ): Unified data are no longer supported. Switching to typed data.\n", config.name, config.type); + config.sql_table = pgsql_table_v8; + } if (config.sql_table_version == 7) { Log(LOG_WARNING, "WARN ( %s/%s ): Unified data are no longer supported. Switching to typed data.\n", config.name, config.type); config.sql_table = pgsql_table_v7; diff -Nru pmacct-0.12.1/src/pgsql_plugin.h pmacct-0.12.5/src/pgsql_plugin.h --- pmacct-0.12.1/src/pgsql_plugin.h 2009-07-14 15:00:13.000000000 +0000 +++ pmacct-0.12.5/src/pgsql_plugin.h 2010-10-06 07:26:12.000000000 +0000 @@ -54,6 +54,7 @@ static char pgsql_table_v5[] = "acct_v5"; static char pgsql_table_v6[] = "acct_v6"; static char pgsql_table_v7[] = "acct_v7"; +static char pgsql_table_v8[] = "acct_v8"; static char pgsql_table_bgp[] = "acct_bgp"; static char pgsql_table_uni[] = "acct_uni"; static char pgsql_table_uni_v2[] = "acct_uni_v2"; diff -Nru pmacct-0.12.1/src/pkt_handlers.c pmacct-0.12.5/src/pkt_handlers.c --- pmacct-0.12.1/src/pkt_handlers.c 2010-03-06 23:43:13.000000000 +0000 +++ pmacct-0.12.5/src/pkt_handlers.c 2010-12-17 13:33:51.000000000 +0000 @@ -62,6 +62,13 @@ else if (config.acct_type == ACCT_SF) channels_list[index].phandler[primitives] = SF_vlan_handler; primitives++; } + + if (channels_list[index].aggregation & COUNT_COS) { + if (config.acct_type == ACCT_PM) channels_list[index].phandler[primitives] = cos_handler; + else if (config.acct_type == ACCT_NF) channels_list[index].phandler[primitives] = NF_cos_handler; + else if (config.acct_type == ACCT_SF) channels_list[index].phandler[primitives] = SF_cos_handler; + primitives++; + } #endif if (channels_list[index].aggregation & (COUNT_SRC_HOST|COUNT_SRC_NET|COUNT_SUM_HOST|COUNT_SUM_NET)) { @@ -152,15 +159,42 @@ primitives++; } + if (channels_list[index].aggregation & COUNT_PEER_SRC_IP) { + if (config.acct_type == ACCT_PM) primitives--; + else if (config.acct_type == ACCT_NF) { + if (config.nfacctd_as == NF_AS_KEEP) channels_list[index].phandler[primitives] = NF_peer_src_ip_handler; + else if (config.nfacctd_as == NF_AS_NEW) channels_list[index].phandler[primitives] = NF_peer_src_ip_handler; + else if (config.nfacctd_as == NF_AS_BGP) primitives--; /* This is handled elsewhere */ + } + else if (config.acct_type == ACCT_SF) { + if (config.nfacctd_as == NF_AS_KEEP) channels_list[index].phandler[primitives] = SF_peer_src_ip_handler; + else if (config.nfacctd_as == NF_AS_NEW) channels_list[index].phandler[primitives] = SF_peer_src_ip_handler; + else if (config.nfacctd_as == NF_AS_BGP) primitives--; /* This is handled elsewhere */ + } + primitives++; + } + + if (channels_list[index].aggregation & COUNT_PEER_DST_IP) { + if (config.acct_type == ACCT_PM) primitives--; + else if (config.acct_type == ACCT_NF) { + if (config.nfacctd_as == NF_AS_KEEP) channels_list[index].phandler[primitives] = NF_peer_dst_ip_handler; + else if (config.nfacctd_as == NF_AS_NEW) channels_list[index].phandler[primitives] = NF_peer_dst_ip_handler; + else if (config.nfacctd_as == NF_AS_BGP) primitives--; /* This is handled elsewhere */ + } + else if (config.acct_type == ACCT_SF) { + if (config.nfacctd_as == NF_AS_KEEP) channels_list[index].phandler[primitives] = SF_peer_dst_ip_handler; + else if (config.nfacctd_as == NF_AS_NEW) channels_list[index].phandler[primitives] = SF_peer_dst_ip_handler; + else if (config.nfacctd_as == NF_AS_BGP) primitives--; /* This is handled elsewhere */ + } + primitives++; + } + if (channels_list[index].aggregation & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED| - COUNT_AS_PATH|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP|COUNT_PEER_DST_AS| - COUNT_SRC_AS_PATH|COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF) - || (channels_list[index].aggregation & (COUNT_SRC_AS|COUNT_DST_AS) && config.nfacctd_as == NF_AS_BGP)) { - if (config.acct_type != ACCT_PM && channels_list[index].plugin->type.id == PLUGIN_ID_SFPROBE) { - /* Let's basically get out of here this case - XXX: silently */ - } - else if (config.acct_type == ACCT_PM && config.nfacctd_bgp) { + COUNT_AS_PATH|COUNT_PEER_DST_AS| COUNT_SRC_AS_PATH|COUNT_SRC_STD_COMM| + COUNT_SRC_EXT_COMM|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF) + || (channels_list[index].aggregation & (COUNT_SRC_AS|COUNT_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP) && + config.nfacctd_as == NF_AS_BGP)) { + if (config.acct_type == ACCT_PM && config.nfacctd_bgp) { if (channels_list[index].plugin->type.id == PLUGIN_ID_SFPROBE) { channels_list[index].phandler[primitives] = sfprobe_bgp_ext_handler; } @@ -346,8 +380,7 @@ if (channels_list[index].plugin->type.id == PLUGIN_ID_NFPROBE) { if (config.acct_type == ACCT_PM) channels_list[index].phandler[primitives] = nfprobe_extras_handler; - else if (config.acct_type == ACCT_NF) channels_list[index].phandler[primitives] = NF_nfprobe_extras_handler; - else if (config.acct_type == ACCT_SF) channels_list[index].phandler[primitives] = SF_nfprobe_extras_handler; + else primitives--; /* This case is filtered out at startup: getting out silently */ primitives++; } @@ -401,8 +434,7 @@ if (channels_list[index].aggregation & COUNT_PAYLOAD) { if (channels_list[index].plugin->type.id == PLUGIN_ID_SFPROBE) { if (config.acct_type == ACCT_PM) channels_list[index].phandler[primitives] = sfprobe_payload_handler; - else if (config.acct_type == ACCT_NF) channels_list[index].phandler[primitives] = NF_sfprobe_payload_handler; - else if (config.acct_type == ACCT_SF) channels_list[index].phandler[primitives] = SF_sfprobe_payload_handler; + else primitives--; /* This case is filtered out at startup: getting out silently */ } primitives++; } @@ -413,6 +445,16 @@ else channels_list[index].phandler[primitives] = sampling_handler; primitives++; } + + if (channels_list[index].aggregation & COUNT_NONE) { + if (channels_list[index].plugin->type.id == PLUGIN_ID_TEE) { + if (config.acct_type == ACCT_SF) channels_list[index].phandler[primitives] = tee_payload_handler; + if (config.acct_type == ACCT_NF) channels_list[index].phandler[primitives] = tee_payload_handler; + else primitives--; /* This case is filtered out at startup: getting out silently */ + } + primitives++; + } + index++; } @@ -442,6 +484,19 @@ if (pptrs->vlan_ptr) { memcpy(&vlan_id, pptrs->vlan_ptr, 2); pdata->primitives.vlan_id = ntohs(vlan_id); + pdata->primitives.vlan_id = pdata->primitives.vlan_id & 0x0FFF; + } +} + +void cos_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ + struct pkt_data *pdata = (struct pkt_data *) *data; + u_int16_t cos = 0; + + if (pptrs->vlan_ptr) { + memcpy(&cos, pptrs->vlan_ptr, 2); + cos = ntohs(cos); + pdata->primitives.cos = cos >> 13; } } #endif @@ -673,6 +728,14 @@ payload->tag2 = pptrs->tag2; if (pptrs->ifindex_in > 0) payload->ifindex_in = pptrs->ifindex_in; if (pptrs->ifindex_out > 0) payload->ifindex_out = pptrs->ifindex_out; + if (pptrs->vlan_ptr) { + u_int16_t vlan_id = 0; + + memcpy(&vlan_id, pptrs->vlan_ptr, 2); + vlan_id = ntohs(vlan_id); + payload->vlan = vlan_id & 0x0FFF; + payload->priority = vlan_id >> 13; + } /* Typically don't have L2 info under ULOG */ if (!pptrs->mac_ptr) { @@ -704,11 +767,23 @@ } } +void tee_payload_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ + struct pkt_msg *pmsg = (struct pkt_msg *) *data; + + pmsg->seqno = pptrs->seqno; + pmsg->len = pptrs->f_len; + memcpy(&pmsg->agent, pptrs->f_agent, sizeof(pmsg->agent)); + memcpy(&pmsg->payload, pptrs->f_header, MIN(sizeof(pmsg->payload), pptrs->f_len)); +} + void nfprobe_extras_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct pkt_data *pdata = (struct pkt_data *) *data; struct pkt_extras *pextras = (struct pkt_extras *) ++pdata; + --pdata; /* Bringing back to original place */ + if (pptrs->mpls_ptr) memcpy(&pextras->mpls_top_label, pptrs->mpls_ptr, 4); if (pptrs->l4_proto == IPPROTO_TCP) pextras->tcp_flags = pptrs->tcp_flags; } @@ -733,10 +808,17 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + u_int8_t direction = 0; switch(hdr->version) { case 9: - memcpy(&pdata->primitives.eth_shost, pptrs->f_data+tpl->tpl[NF9_SRC_MAC].off, MIN(tpl->tpl[NF9_SRC_MAC].len, 6)); + if (tpl->tpl[NF9_DIRECTION].len == 1) + memcpy(&direction, pptrs->f_data+tpl->tpl[NF9_DIRECTION].off, 1); + + if (!direction) + memcpy(&pdata->primitives.eth_shost, pptrs->f_data+tpl->tpl[NF9_IN_SRC_MAC].off, MIN(tpl->tpl[NF9_IN_SRC_MAC].len, 6)); + else + memcpy(&pdata->primitives.eth_shost, pptrs->f_data+tpl->tpl[NF9_OUT_SRC_MAC].off, MIN(tpl->tpl[NF9_OUT_SRC_MAC].len, 6)); break; default: break; @@ -748,10 +830,17 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + u_int8_t direction = 0; switch(hdr->version) { case 9: - memcpy(&pdata->primitives.eth_dhost, pptrs->f_data+tpl->tpl[NF9_DST_MAC].off, MIN(tpl->tpl[NF9_DST_MAC].len, 6)); + if (tpl->tpl[NF9_DIRECTION].len == 1) + memcpy(&direction, pptrs->f_data+tpl->tpl[NF9_DIRECTION].off, 1); + + if (!direction) + memcpy(&pdata->primitives.eth_dhost, pptrs->f_data+tpl->tpl[NF9_IN_DST_MAC].off, MIN(tpl->tpl[NF9_IN_DST_MAC].len, 6)); + else + memcpy(&pdata->primitives.eth_dhost, pptrs->f_data+tpl->tpl[NF9_OUT_DST_MAC].off, MIN(tpl->tpl[NF9_OUT_DST_MAC].len, 6)); break; default: break; @@ -763,16 +852,28 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + u_int8_t direction = 0; switch(hdr->version) { case 9: - memcpy(&pdata->primitives.vlan_id, pptrs->f_data+tpl->tpl[NF9_SRC_VLAN].off, MIN(tpl->tpl[NF9_SRC_VLAN].len, 2)); + if (tpl->tpl[NF9_DIRECTION].len == 1) + memcpy(&direction, pptrs->f_data+tpl->tpl[NF9_DIRECTION].off, 1); + + if (!direction) + memcpy(&pdata->primitives.vlan_id, pptrs->f_data+tpl->tpl[NF9_IN_VLAN].off, MIN(tpl->tpl[NF9_IN_VLAN].len, 2)); + else + memcpy(&pdata->primitives.vlan_id, pptrs->f_data+tpl->tpl[NF9_OUT_VLAN].off, MIN(tpl->tpl[NF9_OUT_VLAN].len, 2)); + pdata->primitives.vlan_id = ntohs(pdata->primitives.vlan_id); break; default: break; } } + +void NF_cos_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ +} #endif void NF_src_host_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) @@ -785,15 +886,27 @@ switch(hdr->version) { case 9: if (pptrs->l3_proto == ETHERTYPE_IP) { - memcpy(&pdata->primitives.src_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_IPV4_SRC_ADDR].off, MIN(tpl->tpl[NF9_IPV4_SRC_ADDR].len, 4)); - memcpy(&src_mask, pptrs->f_data+tpl->tpl[NF9_SRC_MASK].off, tpl->tpl[NF9_SRC_MASK].len); + if (chptr->plugin->cfg.xlate_src && tpl->tpl[NF9_XLATE_IPV4_SRC_ADDR].len) { + memcpy(&pdata->primitives.src_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_XLATE_IPV4_SRC_ADDR].off, MIN(tpl->tpl[NF9_XLATE_IPV4_SRC_ADDR].len, 4)); + src_mask = 32; /* no xlate mask field exists atm */ + } + else { + memcpy(&pdata->primitives.src_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_IPV4_SRC_ADDR].off, MIN(tpl->tpl[NF9_IPV4_SRC_ADDR].len, 4)); + memcpy(&src_mask, pptrs->f_data+tpl->tpl[NF9_SRC_MASK].off, tpl->tpl[NF9_SRC_MASK].len); + } pdata->primitives.src_ip.family = AF_INET; break; } #if defined ENABLE_IPV6 if (pptrs->l3_proto == ETHERTYPE_IPV6) { - memcpy(&pdata->primitives.src_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_IPV6_SRC_ADDR].off, MIN(tpl->tpl[NF9_IPV6_SRC_ADDR].len, 16)); - memcpy(&src_mask, pptrs->f_data+tpl->tpl[NF9_IPV6_SRC_MASK].off, tpl->tpl[NF9_IPV6_SRC_MASK].len); + if (chptr->plugin->cfg.xlate_src && tpl->tpl[NF9_XLATE_IPV6_SRC_ADDR].len) { + memcpy(&pdata->primitives.src_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_XLATE_IPV6_SRC_ADDR].off, MIN(tpl->tpl[NF9_XLATE_IPV6_SRC_ADDR].len, 16)); + src_mask = 128; + } + else { + memcpy(&pdata->primitives.src_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_IPV6_SRC_ADDR].off, MIN(tpl->tpl[NF9_IPV6_SRC_ADDR].len, 16)); + memcpy(&src_mask, pptrs->f_data+tpl->tpl[NF9_IPV6_SRC_MASK].off, tpl->tpl[NF9_IPV6_SRC_MASK].len); + } pdata->primitives.src_ip.family = AF_INET6; break; } @@ -880,15 +993,27 @@ switch(hdr->version) { case 9: if (pptrs->l3_proto == ETHERTYPE_IP) { - memcpy(&pdata->primitives.dst_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_IPV4_DST_ADDR].off, MIN(tpl->tpl[NF9_IPV4_DST_ADDR].len, 4)); - memcpy(&dst_mask, pptrs->f_data+tpl->tpl[NF9_DST_MASK].off, tpl->tpl[NF9_DST_MASK].len); + if (chptr->plugin->cfg.xlate_dst && tpl->tpl[NF9_XLATE_IPV4_DST_ADDR].len) { + memcpy(&pdata->primitives.dst_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_XLATE_IPV4_DST_ADDR].off, MIN(tpl->tpl[NF9_XLATE_IPV4_DST_ADDR].len, 4)); + dst_mask = 32; /* no xlate mask field exists atm */ + } + else { + memcpy(&pdata->primitives.dst_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_IPV4_DST_ADDR].off, MIN(tpl->tpl[NF9_IPV4_DST_ADDR].len, 4)); + memcpy(&dst_mask, pptrs->f_data+tpl->tpl[NF9_DST_MASK].off, tpl->tpl[NF9_DST_MASK].len); + } pdata->primitives.dst_ip.family = AF_INET; break; } #if defined ENABLE_IPV6 if (pptrs->l3_proto == ETHERTYPE_IPV6) { - memcpy(&pdata->primitives.dst_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_IPV6_DST_ADDR].off, MIN(tpl->tpl[NF9_IPV6_DST_ADDR].len, 16)); - memcpy(&dst_mask, pptrs->f_data+tpl->tpl[NF9_IPV6_DST_MASK].off, tpl->tpl[NF9_IPV6_DST_MASK].len); + if (chptr->plugin->cfg.xlate_dst && tpl->tpl[NF9_XLATE_IPV6_DST_ADDR].len) { + memcpy(&pdata->primitives.dst_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_XLATE_IPV6_DST_ADDR].off, MIN(tpl->tpl[NF9_XLATE_IPV6_DST_ADDR].len, 16)); + dst_mask = 128; + } + else { + memcpy(&pdata->primitives.dst_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_IPV6_DST_ADDR].off, MIN(tpl->tpl[NF9_IPV6_DST_ADDR].len, 16)); + memcpy(&dst_mask, pptrs->f_data+tpl->tpl[NF9_IPV6_DST_MASK].off, tpl->tpl[NF9_IPV6_DST_MASK].len); + } pdata->primitives.dst_ip.family = AF_INET6; break; } @@ -977,7 +1102,16 @@ switch(hdr->version) { case 9: - memcpy(&pdata->primitives.src_nmask, pptrs->f_data+tpl->tpl[NF9_SRC_MASK].off, tpl->tpl[NF9_SRC_MASK].len); + if (pptrs->l3_proto == ETHERTYPE_IP) { + memcpy(&pdata->primitives.src_nmask, pptrs->f_data+tpl->tpl[NF9_SRC_MASK].off, tpl->tpl[NF9_SRC_MASK].len); + break; + } +#if defined ENABLE_IPV6 + if (pptrs->l3_proto == ETHERTYPE_IPV6) { + memcpy(&pdata->primitives.src_nmask, pptrs->f_data+tpl->tpl[NF9_IPV6_SRC_MASK].off, tpl->tpl[NF9_IPV6_SRC_MASK].len); + break; + } +#endif break; case 8: switch(hdr->aggregation) { @@ -1015,7 +1149,16 @@ switch(hdr->version) { case 9: - memcpy(&pdata->primitives.dst_nmask, pptrs->f_data+tpl->tpl[NF9_DST_MASK].off, tpl->tpl[NF9_DST_MASK].len); + if (pptrs->l3_proto == ETHERTYPE_IP) { + memcpy(&pdata->primitives.dst_nmask, pptrs->f_data+tpl->tpl[NF9_DST_MASK].off, tpl->tpl[NF9_DST_MASK].len); + break; + } +#if defined ENABLE_IPV6 + if (pptrs->l3_proto == ETHERTYPE_IPV6) { + memcpy(&pdata->primitives.dst_nmask, pptrs->f_data+tpl->tpl[NF9_IPV6_DST_MASK].off, tpl->tpl[NF9_IPV6_DST_MASK].len); + break; + } +#endif break; case 8: switch(hdr->aggregation) { @@ -1145,17 +1288,80 @@ } } +void NF_peer_src_ip_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ + struct pkt_data *pdata = (struct pkt_data *) *data; + struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; + struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; + struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent; + + --pdata; /* Bringing back to original place */ + + if (sa->sa_family == AF_INET) { + pbgp->peer_src_ip.address.ipv4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + pbgp->peer_src_ip.family = AF_INET; + } +#if defined ENABLE_IPV6 + else if (sa->sa_family == AF_INET6) { + memcpy(&pbgp->peer_src_ip.address.ipv6, &((struct sockaddr_in6 *)sa)->sin6_addr, IP6AddrSz); + pbgp->peer_src_ip.family = AF_INET6; + } +#endif +} + +void NF_peer_dst_ip_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ + struct pkt_data *pdata = (struct pkt_data *) *data; + struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; + struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; + + --pdata; /* Bringing back to original place */ + + switch(hdr->version) { + case 9: + if (pptrs->l3_proto == ETHERTYPE_IP) { + memcpy(&pbgp->peer_dst_ip.address.ipv4, pptrs->f_data+tpl->tpl[NF9_BGP_IPV4_NEXT_HOP].off, MIN(tpl->tpl[NF9_BGP_IPV4_NEXT_HOP].len, 4)); + pbgp->peer_dst_ip.family = AF_INET; + break; + } +#if defined ENABLE_IPV6 + if (pptrs->l3_proto == ETHERTYPE_IPV6) { + memcpy(&pbgp->peer_dst_ip.address.ipv6, pptrs->f_data+tpl->tpl[NF9_BGP_IPV6_NEXT_HOP].off, MIN(tpl->tpl[NF9_BGP_IPV6_NEXT_HOP].len, 16)); + pbgp->peer_dst_ip.family = AF_INET6; + break; + } +#endif + break; + case 8: + default: + break; + } +} + void NF_src_port_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + u_int8_t l4_proto = 0; switch(hdr->version) { case 9: - if (((u_int8_t)*(pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off) == IPPROTO_UDP) || - ((u_int8_t)*(pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off) == IPPROTO_TCP)) { - memcpy(&pdata->primitives.src_port, pptrs->f_data+tpl->tpl[NF9_L4_SRC_PORT].off, MIN(tpl->tpl[NF9_L4_SRC_PORT].len, 2)); + if (tpl->tpl[NF9_L4_PROTOCOL].len == 1) + memcpy(&l4_proto, pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off, 1); + + if (l4_proto == IPPROTO_UDP || l4_proto == IPPROTO_TCP) { + if (chptr->plugin->cfg.xlate_src && tpl->tpl[NF9_XLATE_L4_SRC_PORT].len) + memcpy(&pdata->primitives.src_port, pptrs->f_data+tpl->tpl[NF9_XLATE_L4_SRC_PORT].off, MIN(tpl->tpl[NF9_XLATE_L4_SRC_PORT].len, 2)); + else if (tpl->tpl[NF9_L4_SRC_PORT].len) + memcpy(&pdata->primitives.src_port, pptrs->f_data+tpl->tpl[NF9_L4_SRC_PORT].off, MIN(tpl->tpl[NF9_L4_SRC_PORT].len, 2)); + else if (l4_proto == IPPROTO_UDP && tpl->tpl[NF9_UDP_SRC_PORT].len) + memcpy(&pdata->primitives.src_port, pptrs->f_data+tpl->tpl[NF9_UDP_SRC_PORT].off, MIN(tpl->tpl[NF9_UDP_SRC_PORT].len, 2)); + else if (l4_proto == IPPROTO_TCP && tpl->tpl[NF9_TCP_SRC_PORT].len) + memcpy(&pdata->primitives.src_port, pptrs->f_data+tpl->tpl[NF9_TCP_SRC_PORT].off, MIN(tpl->tpl[NF9_TCP_SRC_PORT].len, 2)); + pdata->primitives.src_port = ntohs(pdata->primitives.src_port); } else pdata->primitives.src_port = 0; @@ -1202,12 +1408,23 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; + u_int8_t l4_proto = 0; switch(hdr->version) { case 9: - if (((u_int8_t)*(pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off) == IPPROTO_UDP) || - ((u_int8_t)*(pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off) == IPPROTO_TCP)) { - memcpy(&pdata->primitives.dst_port, pptrs->f_data+tpl->tpl[NF9_L4_DST_PORT].off, MIN(tpl->tpl[NF9_L4_DST_PORT].len, 2)); + if (tpl->tpl[NF9_L4_PROTOCOL].len == 1) + memcpy(&l4_proto, pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off, 1); + + if (l4_proto == IPPROTO_UDP || l4_proto == IPPROTO_TCP) { + if (chptr->plugin->cfg.xlate_dst && tpl->tpl[NF9_XLATE_L4_DST_PORT].len) + memcpy(&pdata->primitives.dst_port, pptrs->f_data+tpl->tpl[NF9_XLATE_L4_DST_PORT].off, MIN(tpl->tpl[NF9_XLATE_L4_DST_PORT].len, 2)); + else if (tpl->tpl[NF9_L4_DST_PORT].len) + memcpy(&pdata->primitives.dst_port, pptrs->f_data+tpl->tpl[NF9_L4_DST_PORT].off, MIN(tpl->tpl[NF9_L4_DST_PORT].len, 2)); + else if (l4_proto == IPPROTO_UDP && tpl->tpl[NF9_UDP_DST_PORT].len) + memcpy(&pdata->primitives.dst_port, pptrs->f_data+tpl->tpl[NF9_UDP_DST_PORT].off, MIN(tpl->tpl[NF9_UDP_DST_PORT].len, 2)); + else if (l4_proto == IPPROTO_TCP && tpl->tpl[NF9_TCP_DST_PORT].len) + memcpy(&pdata->primitives.dst_port, pptrs->f_data+tpl->tpl[NF9_TCP_DST_PORT].off, MIN(tpl->tpl[NF9_TCP_DST_PORT].len, 2)); + pdata->primitives.dst_port = ntohs(pdata->primitives.dst_port); } else pdata->primitives.dst_port = 0; @@ -1363,32 +1580,79 @@ time_t fstime = 0; u_int32_t t32 = 0; u_int64_t t64 = 0; + u_int8_t direction = 0; switch(hdr->version) { case 9: - if (tpl->tpl[NF9_IN_BYTES].len == 4) { - memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 4); - pdata->pkt_len = ntohl(t32); - } - else if (tpl->tpl[NF9_IN_BYTES].len == 8) { - memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 8); - pdata->pkt_len = pm_ntohll(t64); - } - if (tpl->tpl[NF9_IN_PACKETS].len == 4) { - memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 4); - pdata->pkt_num = ntohl(t32); + if (tpl->tpl[NF9_DIRECTION].len == 1) + memcpy(&direction, pptrs->f_data+tpl->tpl[NF9_DIRECTION].off, 1); + + if (!direction) { + if (tpl->tpl[NF9_IN_BYTES].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 4); + pdata->pkt_len = ntohl(t32); + } + else if (tpl->tpl[NF9_IN_BYTES].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 8); + pdata->pkt_len = pm_ntohll(t64); + } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 4); + pdata->pkt_len = ntohl(t32); + } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 8); + pdata->pkt_len = pm_ntohll(t64); + } + + if (tpl->tpl[NF9_IN_PACKETS].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 4); + pdata->pkt_num = ntohl(t32); + } + else if (tpl->tpl[NF9_IN_PACKETS].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 8); + pdata->pkt_num = pm_ntohll(t64); + } } - else if (tpl->tpl[NF9_IN_PACKETS].len == 8) { - memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 8); - pdata->pkt_num = pm_ntohll(t64); + else { + if (tpl->tpl[NF9_OUT_BYTES].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_OUT_BYTES].off, 4); + pdata->pkt_len = ntohl(t32); + } + else if (tpl->tpl[NF9_OUT_BYTES].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_OUT_BYTES].off, 8); + pdata->pkt_len = pm_ntohll(t64); + } + + if (tpl->tpl[NF9_OUT_PACKETS].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_OUT_PACKETS].off, 4); + pdata->pkt_num = ntohl(t32); + } + else if (tpl->tpl[NF9_OUT_PACKETS].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_OUT_PACKETS].off, 8); + pdata->pkt_num = pm_ntohll(t64); + } } - memcpy(&fstime, pptrs->f_data+tpl->tpl[NF9_FIRST_SWITCHED].off, tpl->tpl[NF9_FIRST_SWITCHED].len); - pdata->time_start = ntohl(((struct struct_header_v9 *) pptrs->f_header)->unix_secs)- - ((ntohl(((struct struct_header_v9 *) pptrs->f_header)->SysUptime)-ntohl(fstime))/1000); - memcpy(&fstime, pptrs->f_data+tpl->tpl[NF9_LAST_SWITCHED].off, tpl->tpl[NF9_LAST_SWITCHED].len); - pdata->time_end = ntohl(((struct struct_header_v9 *) pptrs->f_header)->unix_secs)- - ((ntohl(((struct struct_header_v9 *) pptrs->f_header)->SysUptime)-ntohl(fstime))/1000); + if (tpl->tpl[NF9_FIRST_SWITCHED].len || tpl->tpl[NF9_LAST_SWITCHED].len) { + memcpy(&fstime, pptrs->f_data+tpl->tpl[NF9_FIRST_SWITCHED].off, tpl->tpl[NF9_FIRST_SWITCHED].len); + pdata->time_start = ntohl(((struct struct_header_v9 *) pptrs->f_header)->unix_secs)- + ((ntohl(((struct struct_header_v9 *) pptrs->f_header)->SysUptime)-ntohl(fstime))/1000); + memcpy(&fstime, pptrs->f_data+tpl->tpl[NF9_LAST_SWITCHED].off, tpl->tpl[NF9_LAST_SWITCHED].len); + pdata->time_end = ntohl(((struct struct_header_v9 *) pptrs->f_header)->unix_secs)- + ((ntohl(((struct struct_header_v9 *) pptrs->f_header)->SysUptime)-ntohl(fstime))/1000); + } + else if (tpl->tpl[NF9_FIRST_SWITCHED_MSEC].len || tpl->tpl[NF9_FIRST_SWITCHED_MSEC].len) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_FIRST_SWITCHED_MSEC].off, tpl->tpl[NF9_FIRST_SWITCHED_MSEC].len); + pdata->time_start = pm_ntohll(t64)/1000; + + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_LAST_SWITCHED_MSEC].off, tpl->tpl[NF9_LAST_SWITCHED_MSEC].len); + pdata->time_end = pm_ntohll(t64)/1000; + } + else if (tpl->tpl[NF9_OBSERVATION_TIME_MSEC].len) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_OBSERVATION_TIME_MSEC].off, tpl->tpl[NF9_OBSERVATION_TIME_MSEC].len); + pdata->time_start = pm_ntohll(t64)/1000; + } break; case 8: switch(hdr->aggregation) { @@ -1457,6 +1721,15 @@ memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 8); pdata->pkt_len = pm_ntohll(t64); } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 4); + pdata->pkt_len = ntohl(t32); + } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 8); + pdata->pkt_len = pm_ntohll(t64); + } + if (tpl->tpl[NF9_IN_PACKETS].len == 4) { memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 4); pdata->pkt_num = ntohl(t32); @@ -1539,6 +1812,15 @@ memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_IN_BYTES].off, 8); pdata->pkt_len = pm_ntohll(t64); } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 4) { + memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 4); + pdata->pkt_len = ntohl(t32); + } + else if (tpl->tpl[NF9_FLOW_BYTES].len == 8) { + memcpy(&t64, pptrs->f_data+tpl->tpl[NF9_FLOW_BYTES].off, 8); + pdata->pkt_len = pm_ntohll(t64); + } + if (tpl->tpl[NF9_IN_PACKETS].len == 4) { memcpy(&t32, pptrs->f_data+tpl->tpl[NF9_IN_PACKETS].off, 4); pdata->pkt_num = ntohl(t32); @@ -1633,68 +1915,6 @@ } } -void NF_sfprobe_payload_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) -{ - struct pkt_payload *payload = (struct pkt_payload *) *data; - struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; - struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; - struct pkt_data tmp; - char *buf = (char *) *data, *tmpp = (char *) &tmp; - int space = (chptr->bufend - chptr->bufptr) - PpayloadSz; - - NF_counters_msecs_handler(chptr, pptrs, &tmpp); - NF_class_handler(chptr, pptrs, &tmpp); - NF_id_handler(chptr, pptrs, &tmpp); /* XXX: conditional? */ - NF_id2_handler(chptr, pptrs, &tmpp); /* XXX: conditional? */ - NF_src_host_handler(chptr, pptrs, &tmpp); - NF_dst_host_handler(chptr, pptrs, &tmpp); - - payload->cap_len = ((struct pcap_pkthdr *)pptrs->pkthdr)->caplen; /* XXX */ - payload->pkt_len = tmp.pkt_len; - payload->pkt_num = tmp.pkt_num; - payload->time_start = tmp.time_start; - payload->class = tmp.primitives.class; - payload->tag = tmp.primitives.id; - payload->tag2 = tmp.primitives.id2; - - if (chptr->plugin->cfg.nfacctd_as == NF_AS_NEW) { - memcpy(&payload->src_ip, &tmp.primitives.src_ip, HostAddrSz); - memcpy(&payload->dst_ip, &tmp.primitives.dst_ip, HostAddrSz); - } - - if (space >= payload->cap_len) { - buf += PpayloadSz; - memcpy(buf, pptrs->packet_ptr, payload->cap_len); - chptr->bufptr += payload->cap_len; /* don't count pkt_payload here */ - } - else { - chptr->bufptr += space; - chptr->reprocess = TRUE; - } -} - -void NF_nfprobe_extras_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) -{ - struct pkt_data *pdata = (struct pkt_data *) *data; - struct pkt_extras *pextras = (struct pkt_extras *) ++pdata; - struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; - struct template_cache_entry *tpl = (struct template_cache_entry *) pptrs->f_tpl; - - switch(hdr->version) { - case 9: - if (tpl->tpl[NF9_MPLS_LABEL_1].len) - memcpy(&pextras->mpls_top_label, pptrs->f_data+tpl->tpl[NF9_MPLS_LABEL_1].off, MIN(tpl->tpl[NF9_MPLS_LABEL_1].len, 4)); - if ((u_int8_t)*(pptrs->f_data+tpl->tpl[NF9_L4_PROTOCOL].off) == IPPROTO_TCP) - memcpy(&pextras->tcp_flags, pptrs->f_data+tpl->tpl[NF9_TCP_FLAGS].off, tpl->tpl[NF9_TCP_FLAGS].len); - break; - default: - pextras->mpls_top_label = 0; - if (((struct struct_export_v5 *) pptrs->f_data)->prot == IPPROTO_TCP && hdr->version == 5) - pextras->tcp_flags = ((struct struct_export_v5 *) pptrs->f_data)->tcp_flags; - break; - } -} - void NF_in_iface_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct pkt_data *pdata = (struct pkt_data *) *data; @@ -1854,7 +2074,7 @@ switch(hdr->version) { case 9: - if (tpl->tpl[NF9_CUST_CLASS].len) { + if (tpl->tpl[NF9_APPLICATION_ID].len) { pdata->primitives.class = pptrs->class; pdata->cst.ba = 0; pdata->cst.pa = 0; @@ -1913,7 +2133,7 @@ void NF_counters_renormalize_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; - struct xflow_status_entry_sampling *sentry; + struct xflow_status_entry_sampling *sentry = NULL; struct pkt_data *pdata = (struct pkt_data *) *data; struct struct_header_v8 *hdr = (struct struct_header_v8 *) pptrs->f_header; struct struct_header_v5 *hdr5 = (struct struct_header_v5 *) pptrs->f_header; @@ -1924,7 +2144,7 @@ switch (hdr->version) { case 9: memcpy(&sampler_id, pptrs->f_data+tpl->tpl[NF9_FLOW_SAMPLER_ID].off, MIN(tpl->tpl[NF9_FLOW_SAMPLER_ID].len, 1)); - sentry = search_smp_id_status_table(entry->sampling, sampler_id); + if (entry) sentry = search_smp_id_status_table(entry->sampling, sampler_id); if (sentry) { pdata->pkt_len = pdata->pkt_len * sentry->sample_pool; pdata->pkt_num = pdata->pkt_num * sentry->sample_pool; @@ -1958,7 +2178,7 @@ --pdata; /* Bringing back to original place */ if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (config.nfacctd_as == NF_AS_BGP) { if (chptr->aggregation & COUNT_SRC_AS && info->attr->aspath) { @@ -1976,8 +2196,10 @@ } if (chptr->aggregation & COUNT_SRC_AS_PATH && config.nfacctd_bgp_src_as_path_type == BGP_SRC_PRIMITIVES_BGP && info->attr->aspath && info->attr->aspath->str) { strlcpy(pbgp->src_as_path, info->attr->aspath->str, MAX_BGP_ASPATH); - if (strlen(info->attr->aspath->str) >= MAX_BGP_ASPATH) - pbgp->src_as_path[MAX_BGP_ASPATH-1] = '+'; + if (strlen(info->attr->aspath->str) >= MAX_BGP_ASPATH) { + pbgp->src_as_path[MAX_BGP_ASPATH-2] = '+'; + pbgp->src_as_path[MAX_BGP_ASPATH-1] = '\0'; + } if (config.nfacctd_bgp_aspath_radius) evaluate_bgp_aspath_radius(pbgp->src_as_path, MAX_BGP_ASPATH, config.nfacctd_bgp_aspath_radius); } @@ -1986,8 +2208,10 @@ evaluate_comm_patterns(pbgp->src_std_comms, info->attr->community->str, std_comm_patterns, MAX_BGP_STD_COMMS); else { strlcpy(pbgp->src_std_comms, info->attr->community->str, MAX_BGP_STD_COMMS); - if (strlen(info->attr->community->str) >= MAX_BGP_STD_COMMS) - pbgp->src_std_comms[MAX_BGP_STD_COMMS-1] = '+'; + if (strlen(info->attr->community->str) >= MAX_BGP_STD_COMMS) { + pbgp->src_std_comms[MAX_BGP_STD_COMMS-2] = '+'; + pbgp->src_std_comms[MAX_BGP_STD_COMMS-1] = '\0'; + } } } if (chptr->aggregation & COUNT_SRC_EXT_COMM && config.nfacctd_bgp_src_ext_comm_type == BGP_SRC_PRIMITIVES_BGP && info->attr->ecommunity && info->attr->ecommunity->str) { @@ -1995,8 +2219,10 @@ evaluate_comm_patterns(pbgp->src_ext_comms, info->attr->ecommunity->str, ext_comm_patterns, MAX_BGP_EXT_COMMS); else { strlcpy(pbgp->src_ext_comms, info->attr->ecommunity->str, MAX_BGP_EXT_COMMS); - if (strlen(info->attr->ecommunity->str) >= MAX_BGP_EXT_COMMS) - pbgp->src_ext_comms[MAX_BGP_EXT_COMMS-1] = '+'; + if (strlen(info->attr->ecommunity->str) >= MAX_BGP_EXT_COMMS) { + pbgp->src_ext_comms[MAX_BGP_EXT_COMMS-2] = '+'; + pbgp->src_ext_comms[MAX_BGP_EXT_COMMS-1] = '\0'; + } } } if (chptr->aggregation & COUNT_SRC_LOCAL_PREF && config.nfacctd_bgp_src_local_pref_type == BGP_SRC_PRIMITIVES_BGP) @@ -2021,15 +2247,17 @@ } if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { if (chptr->aggregation & COUNT_STD_COMM && info->attr->community && info->attr->community->str) { if (config.nfacctd_bgp_stdcomm_pattern) evaluate_comm_patterns(pbgp->std_comms, info->attr->community->str, std_comm_patterns, MAX_BGP_STD_COMMS); else { strlcpy(pbgp->std_comms, info->attr->community->str, MAX_BGP_STD_COMMS); - if (strlen(info->attr->community->str) >= MAX_BGP_STD_COMMS) - pbgp->std_comms[MAX_BGP_STD_COMMS-1] = '+'; + if (strlen(info->attr->community->str) >= MAX_BGP_STD_COMMS) { + pbgp->std_comms[MAX_BGP_STD_COMMS-2] = '+'; + pbgp->std_comms[MAX_BGP_STD_COMMS-1] = '\0'; + } } } if (chptr->aggregation & COUNT_EXT_COMM && info->attr->ecommunity && info->attr->ecommunity->str) { @@ -2037,14 +2265,18 @@ evaluate_comm_patterns(pbgp->ext_comms, info->attr->ecommunity->str, ext_comm_patterns, MAX_BGP_EXT_COMMS); else { strlcpy(pbgp->ext_comms, info->attr->ecommunity->str, MAX_BGP_EXT_COMMS); - if (strlen(info->attr->ecommunity->str) >= MAX_BGP_EXT_COMMS) - pbgp->ext_comms[MAX_BGP_EXT_COMMS-1] = '+'; + if (strlen(info->attr->ecommunity->str) >= MAX_BGP_EXT_COMMS) { + pbgp->ext_comms[MAX_BGP_EXT_COMMS-2] = '+'; + pbgp->ext_comms[MAX_BGP_EXT_COMMS-1] = '\0'; + } } } if (chptr->aggregation & COUNT_AS_PATH && info->attr->aspath && info->attr->aspath->str) { strlcpy(pbgp->as_path, info->attr->aspath->str, MAX_BGP_ASPATH); - if (strlen(info->attr->aspath->str) >= MAX_BGP_ASPATH) - pbgp->as_path[MAX_BGP_ASPATH-1] = '+'; + if (strlen(info->attr->aspath->str) >= MAX_BGP_ASPATH) { + pbgp->as_path[MAX_BGP_ASPATH-2] = '+'; + pbgp->as_path[MAX_BGP_ASPATH-1] = '\0'; + } if (config.nfacctd_bgp_aspath_radius) evaluate_bgp_aspath_radius(pbgp->as_path, MAX_BGP_ASPATH, config.nfacctd_bgp_aspath_radius); } @@ -2080,44 +2312,47 @@ } } if (chptr->aggregation & COUNT_PEER_DST_IP) { - struct bgp_node *nh; struct bgp_info *nh_info; - if (pptrs->bgp_nexthop) { - nh = (struct bgp_node *) pptrs->bgp_nexthop; - nh_info = nh->info; - } - else - nh_info = info; + if (config.nfacctd_as == NF_AS_BGP) { + if (pptrs->bgp_nexthop_info) + nh_info = (struct bgp_info *) pptrs->bgp_nexthop_info; + else + nh_info = info; - if (nh_info->attr->mp_nexthop.family == AF_INET) { - pbgp->peer_dst_ip.family = AF_INET; - memcpy(&pbgp->peer_dst_ip.address.ipv4, &nh_info->attr->mp_nexthop.address.ipv4, 4); - } + if (nh_info && nh_info->attr) { + if (nh_info->attr->mp_nexthop.family == AF_INET) { + pbgp->peer_dst_ip.family = AF_INET; + memcpy(&pbgp->peer_dst_ip.address.ipv4, &nh_info->attr->mp_nexthop.address.ipv4, 4); + } #if defined ENABLE_IPV6 - else if (nh_info->attr->mp_nexthop.family == AF_INET6) { - pbgp->peer_dst_ip.family = AF_INET6; - memcpy(&pbgp->peer_dst_ip.address.ipv6, &nh_info->attr->mp_nexthop.address.ipv6, 16); - } + else if (nh_info->attr->mp_nexthop.family == AF_INET6) { + pbgp->peer_dst_ip.family = AF_INET6; + memcpy(&pbgp->peer_dst_ip.address.ipv6, &nh_info->attr->mp_nexthop.address.ipv6, 16); + } #endif - else { - pbgp->peer_dst_ip.family = AF_INET; - pbgp->peer_dst_ip.address.ipv4.s_addr = nh_info->attr->nexthop.s_addr; + else { + pbgp->peer_dst_ip.family = AF_INET; + pbgp->peer_dst_ip.address.ipv4.s_addr = nh_info->attr->nexthop.s_addr; + } + } } } } } if (chptr->aggregation & COUNT_PEER_SRC_IP && peer) { - if (!pptrs->bta) memcpy(&pbgp->peer_src_ip, &peer->addr, sizeof(struct host_addr)); - else { - struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent; + if (config.nfacctd_as == NF_AS_BGP) { + if (!pptrs->bta && !config.nfacctd_bgp_follow_default) memcpy(&pbgp->peer_src_ip, &peer->addr, sizeof(struct host_addr)); + else { + struct sockaddr *sa = (struct sockaddr *) pptrs->f_agent; - pbgp->peer_src_ip.family = sa->sa_family; - if (sa->sa_family == AF_INET) pbgp->peer_src_ip.address.ipv4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; + pbgp->peer_src_ip.family = sa->sa_family; + if (sa->sa_family == AF_INET) pbgp->peer_src_ip.address.ipv4.s_addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; #if defined ENABLE_IPV6 - else if (sa->sa_family == AF_INET6) memcpy(&pbgp->peer_src_ip.address.ipv6, &((struct sockaddr_in6 *)sa)->sin6_addr, 16); + else if (sa->sa_family == AF_INET6) memcpy(&pbgp->peer_src_ip.address.ipv6, &((struct sockaddr_in6 *)sa)->sin6_addr, 16); #endif + } } } } @@ -2131,7 +2366,7 @@ struct bgp_info *info; if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (config.nfacctd_as == NF_AS_BGP) { if (chptr->aggregation & COUNT_SRC_AS && info->attr->aspath) { @@ -2145,7 +2380,7 @@ } if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { if (config.nfacctd_as == NF_AS_BGP) { if (chptr->aggregation & COUNT_DST_AS && info->attr->aspath) { @@ -2154,6 +2389,32 @@ else payload->dst_as = evaluate_first_asn(info->attr->aspath->str); } + + if (chptr->aggregation & COUNT_PEER_DST_IP) { + struct bgp_info *nh_info; + + if (pptrs->bgp_nexthop_info) + nh_info = (struct bgp_info *) pptrs->bgp_nexthop_info; + else + nh_info = info; + + if (nh_info && nh_info->attr) { + if (nh_info->attr->mp_nexthop.family == AF_INET) { + payload->bgp_next_hop.family = AF_INET; + memcpy(&payload->bgp_next_hop.address.ipv4, &nh_info->attr->mp_nexthop.address.ipv4, 4); + } +#if defined ENABLE_IPV6 + else if (nh_info->attr->mp_nexthop.family == AF_INET6) { + payload->bgp_next_hop.family = AF_INET6; + memcpy(&payload->bgp_next_hop.address.ipv6, &nh_info->attr->mp_nexthop.address.ipv6, 16); + } +#endif + else { + payload->bgp_next_hop.family = AF_INET; + payload->bgp_next_hop.address.ipv4.s_addr = nh_info->attr->nexthop.s_addr; + } + } + } } } } @@ -2162,13 +2423,16 @@ void nfprobe_bgp_ext_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct pkt_data *pdata = (struct pkt_data *) *data; + struct pkt_extras *pextras = (struct pkt_extras *) ++pdata; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; + --pdata; /* Bringing back to original place */ + if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (config.nfacctd_as == NF_AS_BGP) { if (chptr->aggregation & COUNT_SRC_AS && info->attr->aspath) { @@ -2182,7 +2446,7 @@ } if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { if (config.nfacctd_as == NF_AS_BGP) { if (chptr->aggregation & COUNT_DST_AS && info->attr->aspath) { @@ -2191,6 +2455,32 @@ else pdata->primitives.dst_as = evaluate_first_asn(info->attr->aspath->str); } + + if (chptr->aggregation & COUNT_PEER_DST_IP) { + struct bgp_info *nh_info; + + if (pptrs->bgp_nexthop_info) + nh_info = (struct bgp_info *) pptrs->bgp_nexthop_info; + else + nh_info = info; + + if (nh_info && nh_info->attr) { + if (nh_info->attr->mp_nexthop.family == AF_INET) { + pextras->bgp_next_hop.family = AF_INET; + memcpy(&pextras->bgp_next_hop.address.ipv4, &nh_info->attr->mp_nexthop.address.ipv4, 4); + } +#if defined ENABLE_IPV6 + else if (nh_info->attr->mp_nexthop.family == AF_INET6) { + pextras->bgp_next_hop.family = AF_INET6; + memcpy(&pextras->bgp_next_hop.address.ipv6, &nh_info->attr->mp_nexthop.address.ipv6, 16); + } +#endif + else { + pextras->bgp_next_hop.family = AF_INET; + pextras->bgp_next_hop.address.ipv4.s_addr = nh_info->attr->nexthop.s_addr; + } + } + } } } } @@ -2201,6 +2491,7 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; --pdata; /* Bringing back to original place */ @@ -2213,7 +2504,7 @@ if (src_ret) { char tmp_stdcomms[MAX_BGP_STD_COMMS]; - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr && info->attr->community && info->attr->community->str) { evaluate_comm_patterns(tmp_stdcomms, info->attr->community->str, std_comm_patterns_to_asn, MAX_BGP_STD_COMMS); @@ -2228,7 +2519,6 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; - struct bgp_info *info; --pdata; /* Bringing back to original place */ @@ -2240,7 +2530,6 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; - struct bgp_info *info; --pdata; /* Bringing back to original place */ @@ -2252,7 +2541,6 @@ struct pkt_data *pdata = (struct pkt_data *) *data; struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; - struct bgp_info *info; --pdata; /* Bringing back to original place */ @@ -2282,6 +2570,16 @@ SFSample *sample = (SFSample *) pptrs->f_data; pdata->primitives.vlan_id = sample->in_vlan; + if (!pdata->primitives.vlan_id) pdata->primitives.vlan_id = sample->out_vlan; +} + +void SF_cos_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +{ + struct pkt_data *pdata = (struct pkt_data *) *data; + SFSample *sample = (SFSample *) pptrs->f_data; + + pdata->primitives.cos = sample->in_priority; + if (!pdata->primitives.cos) pdata->primitives.cos = sample->out_priority; } #endif @@ -2443,12 +2741,12 @@ void SF_counters_renormalize_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct xflow_status_entry *entry = (struct xflow_status_entry *) pptrs->f_status; - struct xflow_status_entry_sampling *sentry; + struct xflow_status_entry_sampling *sentry = NULL; struct pkt_data *pdata = (struct pkt_data *) *data; SFSample *sample = (SFSample *) pptrs->f_data; u_int32_t eff_srate = 0; - sentry = search_smp_if_status_table(entry->sampling, (sample->ds_class << 24 | sample->ds_index)); + if (entry) sentry = search_smp_if_status_table(entry->sampling, (sample->ds_class << 24 | sample->ds_index)); if (sentry) { /* flow sequence number is strictly increasing; however we need a) to avoid a division-by-zero by checking the last value and the new one and b) to @@ -2471,7 +2769,7 @@ } } else { - sentry = create_smp_entry_status_table(entry); + if (entry) sentry = create_smp_entry_status_table(entry); if (sentry) { sentry->interface = (sample->ds_class << 24 | sample->ds_index); sentry->sample_pool = sample->samplePool; @@ -2499,48 +2797,44 @@ pdata->primitives.dst_as = sample->dst_as; } -void SF_sfprobe_payload_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +void SF_peer_src_ip_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { - struct pkt_payload *payload = (struct pkt_payload *) *data; + struct pkt_data *pdata = (struct pkt_data *) *data; + struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; SFSample *sample = (SFSample *) pptrs->f_data; - struct pkt_data tmp; - char *buf = (char *) *data, *tmpp = (char *) &tmp; - int space = (chptr->bufend - chptr->bufptr) - PpayloadSz; - - if (chptr->plugin->cfg.nfacctd_as == NF_AS_NEW) { - SF_src_host_handler(chptr, pptrs, &tmpp); - SF_dst_host_handler(chptr, pptrs, &tmpp); - memcpy(&payload->src_ip, &tmp.primitives.src_ip, HostAddrSz); - memcpy(&payload->dst_ip, &tmp.primitives.dst_ip, HostAddrSz); - } - payload->cap_len = sample->headerLen; - payload->pkt_len = sample->sampledPacketSize; - payload->pkt_len = 1; - payload->time_start = time(NULL); /* XXX */ - payload->class = sample->class; - payload->tag = sample->tag; - payload->tag2 = sample->tag2; + --pdata; /* Bringing back to original place */ - if (space >= payload->cap_len) { - buf += PpayloadSz; - memcpy(buf, sample->header, payload->cap_len); - chptr->bufptr += payload->cap_len; /* don't count pkt_payload here */ + if (sample->agent_addr.type == SFLADDRESSTYPE_IP_V4) { + pbgp->peer_src_ip.address.ipv4.s_addr = sample->agent_addr.address.ip_v4.s_addr; + pbgp->peer_src_ip.family = AF_INET; } - else { - chptr->bufptr += space; - chptr->reprocess = TRUE; +#if defined ENABLE_IPV6 + else if (sample->agent_addr.type == SFLADDRESSTYPE_IP_V6) { + memcpy(&pbgp->peer_src_ip.address.ipv6, &sample->agent_addr.address.ip_v6, IP6AddrSz); + pbgp->peer_src_ip.family = AF_INET6; } +#endif } -void SF_nfprobe_extras_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) +void SF_peer_dst_ip_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) { struct pkt_data *pdata = (struct pkt_data *) *data; - struct pkt_extras *pextras = (struct pkt_extras *) ++pdata; + struct pkt_bgp_primitives *pbgp = (struct pkt_bgp_primitives *) ++pdata; SFSample *sample = (SFSample *) pptrs->f_data; - if (sample->lstk.depth) memcpy(&pextras->mpls_top_label, &sample->lstk.stack[0], 4); - if (sample->dcd_ipProtocol == IPPROTO_TCP) pextras->tcp_flags = sample->dcd_tcpFlags; + --pdata; /* Bringing back to original place */ + + if (sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V4) { + pbgp->peer_dst_ip.address.ipv4.s_addr = sample->bgp_nextHop.address.ip_v4.s_addr; + pbgp->peer_dst_ip.family = AF_INET; + } +#if defined ENABLE_IPV6 + else if (sample->bgp_nextHop.type == SFLADDRESSTYPE_IP_V6) { + memcpy(&pbgp->peer_dst_ip.address.ipv6, &sample->bgp_nextHop.address.ip_v6, IP6AddrSz); + pbgp->peer_dst_ip.family = AF_INET6; + } +#endif } void SF_in_iface_handler(struct channels_list_entry *chptr, struct packet_ptrs *pptrs, char **data) diff -Nru pmacct-0.12.1/src/pkt_handlers.h pmacct-0.12.5/src/pkt_handlers.h --- pmacct-0.12.1/src/pkt_handlers.h 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/pkt_handlers.h 2010-06-07 01:21:57.000000000 +0000 @@ -40,6 +40,7 @@ EXT void src_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void dst_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void vlan_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void cos_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void src_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void dst_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void src_port_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -55,11 +56,13 @@ EXT void in_iface_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void out_iface_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void sfprobe_payload_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void tee_payload_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void nfprobe_extras_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_src_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_dst_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_vlan_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void NF_cos_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_src_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_dst_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_src_nmask_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -68,6 +71,8 @@ EXT void NF_dst_port_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_src_as_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_dst_as_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void NF_peer_src_ip_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void NF_peer_dst_ip_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_ip_tos_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_ip_proto_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_tcp_flags_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -80,8 +85,6 @@ EXT void NF_out_iface_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_id_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_id2_handler(struct channels_list_entry *, struct packet_ptrs *, char **); -EXT void NF_sfprobe_payload_handler(struct channels_list_entry *, struct packet_ptrs *, char **); -EXT void NF_nfprobe_extras_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void NF_counters_renormalize_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void bgp_ext_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -99,6 +102,7 @@ EXT void SF_src_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_dst_mac_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_vlan_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void SF_cos_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_src_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_dst_host_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_src_nmask_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -107,6 +111,8 @@ EXT void SF_dst_port_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_src_as_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_dst_as_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void SF_peer_src_ip_handler(struct channels_list_entry *, struct packet_ptrs *, char **); +EXT void SF_peer_dst_ip_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_ip_tos_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_ip_proto_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_tcp_flags_handler(struct channels_list_entry *, struct packet_ptrs *, char **); @@ -114,8 +120,6 @@ EXT void SF_counters_renormalize_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_id_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_id2_handler(struct channels_list_entry *, struct packet_ptrs *, char **); -EXT void SF_sfprobe_payload_handler(struct channels_list_entry *, struct packet_ptrs *, char **); -EXT void SF_nfprobe_extras_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_class_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_in_iface_handler(struct channels_list_entry *, struct packet_ptrs *, char **); EXT void SF_out_iface_handler(struct channels_list_entry *, struct packet_ptrs *, char **); diff -Nru pmacct-0.12.1/src/plugin_hooks.c pmacct-0.12.5/src/plugin_hooks.c --- pmacct-0.12.1/src/plugin_hooks.c 2009-10-11 15:56:07.000000000 +0000 +++ pmacct-0.12.5/src/plugin_hooks.c 2010-12-07 21:41:06.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -49,7 +49,7 @@ while (list) { if ((*list->type.func)) { - if (list->cfg.data_type & (PIPE_TYPE_METADATA|PIPE_TYPE_PAYLOAD)); + if (list->cfg.data_type & (PIPE_TYPE_METADATA|PIPE_TYPE_PAYLOAD|PIPE_TYPE_MSG)); else { Log(LOG_ERR, "ERROR ( %s/%s ): Data type not supported: %d\n", list->name, list->type.string, list->cfg.data_type); exit(1); @@ -63,6 +63,7 @@ } if (list->cfg.data_type & PIPE_TYPE_EXTRAS) min_sz += PextrasSz; if (list->cfg.data_type & PIPE_TYPE_BGP) min_sz += PbgpSz; + if (list->cfg.data_type & PIPE_TYPE_MSG) min_sz += PmsgSz; /* If nothing is supplied, let's hint some working default values */ if (list->cfg.pcap_savefile && !list->cfg.pipe_size && !list->cfg.buffer_size) { @@ -133,7 +134,7 @@ list->cfg.name = list->name; list->cfg.type = list->type.string; - chptr = insert_pipe_channel(&list->cfg, list->pipe[1]); + chptr = insert_pipe_channel(list->type.id, &list->cfg, list->pipe[1]); if (!chptr) { Log(LOG_ERR, "ERROR: Unable to setup a new Core Process <-> Plugin channel.\nExiting.\n"); exit_all(1); @@ -150,6 +151,7 @@ if (list->cfg.data_type & PIPE_TYPE_PAYLOAD) chptr->clean_func = pkt_payload_clean; if (list->cfg.data_type & PIPE_TYPE_EXTRAS) chptr->clean_func = pkt_extras_clean; if (list->cfg.data_type & PIPE_TYPE_BGP) chptr->clean_func = pkt_bgp_clean; + if (list->cfg.data_type & PIPE_TYPE_MSG) chptr->clean_func = pkt_msg_clean; /* sets nfprobe ID */ if (list->type.id == PLUGIN_ID_NFPROBE) { @@ -264,7 +266,7 @@ } } -struct channels_list_entry *insert_pipe_channel(struct configuration *cfg, int pipe) +struct channels_list_entry *insert_pipe_channel(int plugin_type, struct configuration *cfg, int pipe) { struct channels_list_entry *chptr; int index = 0, x; @@ -278,7 +280,7 @@ chptr->agg_filter.num = (int *) &cfg->bpfp_a_num; chptr->bufsize = cfg->buffer_size; chptr->id = cfg->post_tag; - if (cfg->sampling_rate) { + if (cfg->sampling_rate && plugin_type != PLUGIN_ID_SFPROBE) { /* sfprobe cares for itself */ chptr->s.rate = cfg->sampling_rate; if (cfg->acct_type == ACCT_NF) chptr->s.sf = &take_simple_systematic_skip; @@ -428,8 +430,6 @@ *pkt_len = ( *pkt_len / *pkt_num ) * smp->sampled_pkts; *pkt_num = smp->sampled_pkts; } - - // printf("RATE: %d, COUNTER: %d, PACKETS %d, SAMPLED_PACKETS: %d, SAMPLE_POOL: %d\n", smp->rate, smp->counter, *pkt_num, smp->sampled_pkts, *sample_pool); } /* simple random algorithm */ @@ -551,13 +551,13 @@ /* compiling aggregation filter if needed */ if (list->cfg.a_filter) { pcap_t *dev_desc; - bpf_u_int32 localnet, netmask; /* pcap library stuff */ + bpf_u_int32 localnet, netmask = 0; /* pcap library stuff */ char errbuf[PCAP_ERRBUF_SIZE], *count_token; int idx = 0; dev_desc = pcap_open_dead(link_type, 128); /* 128 bytes should be long enough */ - pcap_lookupnet(config.dev, &localnet, &netmask, errbuf); + if (config.dev) pcap_lookupnet(config.dev, &localnet, &netmask, errbuf); list->cfg.bpfp_a_table[idx] = malloc(sizeof(struct bpf_program)); while ( (count_token = extract_token(&list->cfg.a_filter, ',')) && idx < AGG_FILTER_ENTRIES ) { @@ -592,6 +592,13 @@ return PpayloadSz; } +int pkt_msg_clean(void *ppayload) +{ + memset(ppayload, 0, PmsgSz); + + return PmsgSz; +} + int pkt_extras_clean(void *pextras) { memset(pextras, 0, PdataSz+PextrasSz); diff -Nru pmacct-0.12.1/src/plugin_hooks.h pmacct-0.12.5/src/plugin_hooks.h --- pmacct-0.12.1/src/plugin_hooks.h 2009-10-11 15:56:07.000000000 +0000 +++ pmacct-0.12.5/src/plugin_hooks.h 2010-07-25 23:25:23.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -97,7 +97,7 @@ EXT void load_plugins(struct plugin_requests *); EXT void exec_plugins(struct packet_ptrs *pptrs); EXT void load_plugin_filters(int); -EXT struct channels_list_entry *insert_pipe_channel(struct configuration *, int); +EXT struct channels_list_entry *insert_pipe_channel(int, struct configuration *, int); EXT void delete_pipe_channel(int); EXT void sort_pipe_channels(); EXT void init_pipe_channels(); @@ -109,6 +109,7 @@ EXT int check_shadow_status(struct packet_ptrs *, struct channels_list_entry *); EXT int pkt_data_clean(void *); EXT int pkt_payload_clean(void *); +EXT int pkt_msg_clean(void *); EXT int pkt_extras_clean(void *); EXT int pkt_bgp_clean(void *); EXT void evaluate_sampling(struct sampling *, pm_counter_t *, pm_counter_t *, pm_counter_t *); @@ -126,6 +127,7 @@ EXT void print_plugin(int, struct configuration *, void *); EXT void nfprobe_plugin(int, struct configuration *, void *); EXT void sfprobe_plugin(int, struct configuration *, void *); +EXT void tee_plugin(int, struct configuration *, void *); #ifdef WITH_MYSQL EXT void mysql_plugin(int, struct configuration *, void *); diff -Nru pmacct-0.12.1/src/pmacct.c pmacct-0.12.5/src/pmacct.c --- pmacct-0.12.1/src/pmacct.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/pmacct.c 2010-10-04 14:35:27.000000000 +0000 @@ -62,7 +62,7 @@ printf(" -S\tSum counters instead of returning a single counter for each request (applies to -N)\n"); printf(" -M\t[matching data[';' ... ]] | ['file:'[filename]] \n\tMatch primitives; print formatted table (requires -c)\n"); printf(" -a\tDisplay all table fields (even those currently unused)\n"); - printf(" -c\t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_mask | dst_mask | \n\t src_port | dst_port | tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | \n\t sum_port | in_iface | out_iface | tag | tag2 | flows | class | std_comm | ext_comm | as_path | \n\t peer_src_ip | peer_dst_ip | peer_src_as | peer_dst_as | src_as_path | src_std_comm | src_med | \n\t src_ext_comm | src_local_pref | is_symmetric ] \n\tSelect primitives to match (required by -N and -M)\n"); + printf(" -c\t[ src_mac | dst_mac | vlan | cos | src_host | dst_host | src_net | dst_net | src_mask | dst_mask | \n\t src_port | dst_port | tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | \n\t sum_port | in_iface | out_iface | tag | tag2 | flows | class | std_comm | ext_comm | as_path | \n\t peer_src_ip | peer_dst_ip | peer_src_as | peer_dst_as | src_as_path | src_std_comm | src_med | \n\t src_ext_comm | src_local_pref | is_symmetric ] \n\tSelect primitives to match (required by -N and -M)\n"); printf(" -T\t[bytes|packets|flows] \n\tOutput top N statistics (applies to -M and -s)\n"); printf(" -e\tClear statistics\n"); printf(" -r\tReset counters (applies to -N and -M)\n"); @@ -125,6 +125,7 @@ printf("SRC_MAC "); printf("DST_MAC "); printf("VLAN "); + printf("COS "); #endif printf("SRC_AS "); printf("DST_AS "); @@ -180,6 +181,7 @@ if (what_to_count & (COUNT_SRC_MAC|COUNT_SUM_MAC)) printf("SRC_MAC "); if (what_to_count & COUNT_DST_MAC) printf("DST_MAC "); if (what_to_count & COUNT_VLAN) printf("VLAN "); + if (what_to_count & COUNT_COS) printf("COS "); #endif if (what_to_count & (COUNT_SRC_AS|COUNT_SUM_AS)) printf("SRC_AS "); if (what_to_count & COUNT_DST_AS) printf("DST_AS "); @@ -386,6 +388,15 @@ count_token_int[count_index] = COUNT_VLAN; what_to_count |= COUNT_VLAN; } + else if (!strcmp(count_token[count_index], "cos")) { + count_token_int[count_index] = COUNT_COS; + what_to_count |= COUNT_COS; + } + else if (!strcmp(count_token[count_index], "sum_mac")) { + count_token_int[count_index] = COUNT_SUM_MAC; + what_to_count |= COUNT_SUM_MAC; + } +#endif else if (!strcmp(count_token[count_index], "in_iface")) { count_token_int[count_index] = COUNT_IN_IFACE; what_to_count |= COUNT_IN_IFACE; @@ -394,11 +405,6 @@ count_token_int[count_index] = COUNT_OUT_IFACE; what_to_count |= COUNT_OUT_IFACE; } - else if (!strcmp(count_token[count_index], "sum_mac")) { - count_token_int[count_index] = COUNT_SUM_MAC; - what_to_count |= COUNT_SUM_MAC; - } -#endif else if (!strcmp(count_token[count_index], "tos")) { count_token_int[count_index] = COUNT_IP_TOS; what_to_count |= COUNT_IP_TOS; @@ -794,6 +800,11 @@ else if (!strcmp(count_token[match_string_index], "vlan")) { request.data.vlan_id = atoi(match_string_token); } + else if (!strcmp(count_token[match_string_index], "cos")) { + request.data.cos = atoi(match_string_token); + } +#endif + else if (!strcmp(count_token[match_string_index], "in_iface")) { char *endptr; @@ -804,6 +815,7 @@ request.data.ifindex_out = strtoul(match_string_token, &endptr, 10); } + else if (!strcmp(count_token[match_string_index], "src_mask")) { char *endptr; u_int32_t src_mask; @@ -818,7 +830,7 @@ dst_mask = strtoul(match_string_token, &endptr, 10); request.data.dst_nmask = dst_mask; } -#endif + else if (!strcmp(count_token[match_string_index], "src_port") || !strcmp(count_token[match_string_index], "sum_port")) { request.data.src_port = atoi(match_string_token); @@ -1134,10 +1146,10 @@ !class_table[acc_elem->primitives.class-1].id) ? "unknown" : class_table[acc_elem->primitives.class-1].protocol); if (!have_wtc || (what_to_count & COUNT_IN_IFACE)) { - printf("%-10d ", acc_elem->primitives.ifindex_in); + printf("%-10u ", acc_elem->primitives.ifindex_in); } if (!have_wtc || (what_to_count & COUNT_OUT_IFACE)) { - printf("%-10d ", acc_elem->primitives.ifindex_out); + printf("%-10u ", acc_elem->primitives.ifindex_out); } #if defined (HAVE_L2) @@ -1152,15 +1164,19 @@ } if (!have_wtc || (what_to_count & COUNT_VLAN)) { - printf("%-5d ", acc_elem->primitives.vlan_id); + printf("%-5u ", acc_elem->primitives.vlan_id); + } + + if (!have_wtc || (what_to_count & COUNT_COS)) { + printf("%-2u ", acc_elem->primitives.cos); } #endif if (!have_wtc || (what_to_count & (COUNT_SRC_AS|COUNT_SUM_AS))) { - printf("%-10d ", acc_elem->primitives.src_as); + printf("%-10u ", acc_elem->primitives.src_as); } if (!have_wtc || (what_to_count & COUNT_DST_AS)) { - printf("%-10d ", acc_elem->primitives.dst_as); + printf("%-10u ", acc_elem->primitives.dst_as); } /* Slightly special "!have_wtc" handling due to standard and @@ -1238,31 +1254,31 @@ } if (!have_wtc || (what_to_count & COUNT_LOCAL_PREF)) { - printf("%-7d ", pbgp->local_pref); + printf("%-7u ", pbgp->local_pref); } if (!have_wtc || (what_to_count & COUNT_SRC_LOCAL_PREF)) { - printf("%-7d ", pbgp->src_local_pref); + printf("%-7u ", pbgp->src_local_pref); } if (!have_wtc || (what_to_count & COUNT_MED)) { - printf("%-6d ", pbgp->med); + printf("%-6u ", pbgp->med); } if (!have_wtc || (what_to_count & COUNT_SRC_MED)) { - printf("%-6d ", pbgp->src_med); + printf("%-6u ", pbgp->src_med); } if (!have_wtc || (what_to_count & COUNT_IS_SYMMETRIC)) { - printf("%-3d ", pbgp->is_symmetric); + printf("%-3u ", pbgp->is_symmetric); } if (!have_wtc || (what_to_count & COUNT_PEER_SRC_AS)) { - printf("%-10d ", pbgp->peer_src_as); + printf("%-10u ", pbgp->peer_src_as); } if (!have_wtc || (what_to_count & COUNT_PEER_DST_AS)) { - printf("%-10d ", pbgp->peer_dst_as); + printf("%-10u ", pbgp->peer_dst_as); } if (!have_wtc || (what_to_count & COUNT_PEER_SRC_IP)) { @@ -1312,28 +1328,28 @@ } if (!have_wtc || (what_to_count & COUNT_SRC_NMASK)) - printf("%-3d ", acc_elem->primitives.src_nmask); + printf("%-3u ", acc_elem->primitives.src_nmask); if (!have_wtc || (what_to_count & COUNT_DST_NMASK)) - printf("%-3d ", acc_elem->primitives.dst_nmask); + printf("%-3u ", acc_elem->primitives.dst_nmask); if (!have_wtc || (what_to_count & (COUNT_SRC_PORT|COUNT_SUM_PORT))) - printf("%-5d ", acc_elem->primitives.src_port); + printf("%-5u ", acc_elem->primitives.src_port); if (!have_wtc || (what_to_count & COUNT_DST_PORT)) - printf("%-5d ", acc_elem->primitives.dst_port); + printf("%-5u ", acc_elem->primitives.dst_port); if (!have_wtc || (what_to_count & COUNT_TCPFLAGS)) - printf("%-6d ", acc_elem->tcp_flags); + printf("%-6u ", acc_elem->tcp_flags); if (!have_wtc || (what_to_count & COUNT_IP_PROTO)) { if (acc_elem->primitives.proto < protocols_number) printf("%-10s ", _protocols[acc_elem->primitives.proto].name); - else printf("%-3d ", acc_elem->primitives.proto); + else printf("%-3u ", acc_elem->primitives.proto); } if (!have_wtc || (what_to_count & COUNT_IP_TOS)) - printf("%-3d ", acc_elem->primitives.tos); + printf("%-3u ", acc_elem->primitives.tos); #if defined HAVE_64BIT_COUNTERS printf("%-20llu ", acc_elem->pkt_num); diff -Nru pmacct-0.12.1/src/pmacct-data.h pmacct-0.12.5/src/pmacct-data.h --- pmacct-0.12.1/src/pmacct-data.h 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/pmacct-data.h 2010-10-31 22:51:41.000000000 +0000 @@ -28,6 +28,7 @@ #define PLUGIN_ID_MYSQL 5 #define PLUGIN_ID_PGSQL 6 #define PLUGIN_ID_SQLITE3 7 +#define PLUGIN_ID_TEE 8 #define PLUGIN_ID_UNKNOWN -1 /* vars */ @@ -266,6 +267,7 @@ {"print_refresh_time", cfg_key_print_refresh_time}, {"print_cache_entries", cfg_key_print_cache_entries}, {"print_markers", cfg_key_print_markers}, + {"print_output", cfg_key_print_output}, {"nfacctd_port", cfg_key_nfacctd_port}, {"nfacctd_ip", cfg_key_nfacctd_ip}, {"nfacctd_allow_file", cfg_key_nfacctd_allow_file}, @@ -321,16 +323,28 @@ {"nfprobe_version", cfg_key_nfprobe_version}, {"nfprobe_peer_as", cfg_key_nfprobe_peer_as}, {"nfprobe_source_ip", cfg_key_nfprobe_source_ip}, + {"nfprobe_ipprec", cfg_key_nfprobe_ip_precedence}, + {"nfprobe_direction", cfg_key_nfprobe_direction}, + {"nfprobe_ifindex", cfg_key_nfprobe_ifindex}, {"sfprobe_receiver", cfg_key_sfprobe_receiver}, {"sfprobe_agentip", cfg_key_sfprobe_agentip}, {"sfprobe_agentsubid", cfg_key_sfprobe_agentsubid}, {"sfprobe_peer_as", cfg_key_nfprobe_peer_as}, + {"sfprobe_ipprec", cfg_key_nfprobe_ip_precedence}, + {"sfprobe_direction", cfg_key_nfprobe_direction}, + {"sfprobe_ifindex", cfg_key_nfprobe_ifindex}, + {"sfprobe_ifspeed", cfg_key_sfprobe_ifspeed}, + {"tee_receiver", cfg_key_nfprobe_receiver}, + {"tee_source_ip", cfg_key_nfprobe_source_ip}, + {"tee_transparent", cfg_key_tee_transparent}, {"bgp_daemon", cfg_key_nfacctd_bgp}, {"bgp_daemon_ip", cfg_key_nfacctd_bgp_ip}, {"bgp_daemon_port", cfg_key_nfacctd_bgp_port}, {"bgp_daemon_max_peers", cfg_key_nfacctd_bgp_max_peers}, {"bgp_daemon_msglog", cfg_key_nfacctd_bgp_msglog}, {"bgp_daemon_allow_file", cfg_key_nfacctd_bgp_allow_file}, + {"bgp_daemon_ipprec", cfg_key_nfacctd_bgp_ip_precedence}, + {"bgp_daemon_md5_file", cfg_key_nfacctd_bgp_md5_file}, {"bgp_aspath_radius", cfg_key_nfacctd_bgp_aspath_radius}, {"bgp_stdcomm_pattern", cfg_key_nfacctd_bgp_stdcomm_pattern}, {"bgp_extcomm_pattern", cfg_key_nfacctd_bgp_extcomm_pattern}, @@ -350,9 +364,12 @@ {"bgp_follow_default", cfg_key_nfacctd_bgp_follow_default}, {"bgp_follow_nexthop", cfg_key_nfacctd_bgp_follow_nexthop}, {"bgp_neighbors_file", cfg_key_nfacctd_bgp_neighbors_file}, + {"bgp_table_peer_buckets", cfg_key_nfacctd_bgp_table_peer_buckets}, {"uacctd_group", cfg_key_uacctd_group}, {"uacctd_nl_size", cfg_key_uacctd_nl_size}, {"tunnel_0", cfg_key_tunnel_0}, + {"xlate_src", cfg_key_xlate_src}, + {"xlate_dst", cfg_key_xlate_dst}, {"", NULL}, }; @@ -371,6 +388,7 @@ #ifdef WITH_SQLITE3 {PLUGIN_ID_SQLITE3, "sqlite3", sqlite3_plugin}, #endif + {PLUGIN_ID_TEE, "tee", tee_plugin}, {PLUGIN_ID_UNKNOWN, "", NULL}, }; #endif diff -Nru pmacct-0.12.1/src/pmacctd.c pmacct-0.12.5/src/pmacctd.c --- pmacct-0.12.1/src/pmacctd.c 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/pmacctd.c 2010-10-06 07:26:12.000000000 +0000 @@ -53,7 +53,7 @@ printf("\nGeneral options:\n"); printf(" -h \tShow this page\n"); printf(" -f \tLoad configuration from the specified file\n"); - printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t proto | tos | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | none ] \n\tAggregation string (DEFAULT: src_host)\n"); + printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t proto | tos | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | cos | none ] \n\tAggregation string (DEFAULT: src_host)\n"); printf(" -D \tDaemonize\n"); printf(" -N \tDisable promiscuous mode\n"); printf(" -n \tPath to a file containing Network definitions\n"); @@ -68,14 +68,17 @@ printf(" -W \tReading from a savefile, don't exit but sleep when finished\n"); printf(" -R \tRenormalize sampled data\n"); printf(" -L \tSet snapshot length\n"); - printf("\nMemory Plugin (-P memory) options:\n"); + printf("\nMemory plugin (-P memory) options:\n"); printf(" -p \tSocket for client-server communication (DEFAULT: /tmp/collect.pipe)\n"); printf(" -b \tNumber of buckets\n"); printf(" -m \tNumber of memory pools\n"); printf(" -s \tMemory pool size\n"); printf("\nPostgreSQL (-P pgsql)/MySQL (-P mysql)/SQLite (-P sqlite3) plugin options:\n"); printf(" -r \tRefresh time (in seconds)\n"); - printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] \n\tTable version\n"); + printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] \n\tTable version\n"); + printf("\nPrint plugin (-P print) plugin options:\n"); + printf(" -r \tRefresh time (in seconds)\n"); + printf(" -O \t[ formatted | csv ] \n\tOutput format\n"); printf("\n"); printf(" See EXAMPLES or visit http://wiki.pmacct.net/ for examples.\n"); printf("\n"); @@ -180,6 +183,11 @@ strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; + case 'O': + strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN); + strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); + rows++; + break; case 'N': strlcpy(cfg_cmdline[rows], "promisc: false", SRVBUFLEN); rows++; @@ -354,7 +362,12 @@ Log(LOG_ERR, "ERROR: Internal packet sampling and external packet sampling are mutual exclusive.\n"); exit(1); } - if (list->type.id == PLUGIN_ID_NFPROBE) { + + if (list->type.id == PLUGIN_ID_TEE) { + Log(LOG_ERR, "ERROR: 'tee' plugin not supported in 'pmacctd'.\n"); + exit(1); + } + else if (list->type.id == PLUGIN_ID_NFPROBE) { /* If we already renormalizing an external sampling rate, we cancel the sampling information from the probe plugin */ if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; @@ -384,22 +397,23 @@ if (list->cfg.networks_file || (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP)) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; + list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if (list->cfg.nfprobe_version == 9 && list->cfg.classifiers_path) { list->cfg.what_to_count |= COUNT_CLASS; config.handle_flows = TRUE; } - if (list->cfg.nfprobe_version == 9 && list->cfg.pre_tag_map) { + if (list->cfg.pre_tag_map) { list->cfg.what_to_count |= COUNT_ID; list->cfg.what_to_count |= COUNT_ID2; } list->cfg.what_to_count |= COUNT_IN_IFACE; list->cfg.what_to_count |= COUNT_OUT_IFACE; if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); + COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| + COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| + COUNT_IS_SYMMETRIC)) { + Log(LOG_ERR, "ERROR: 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); exit(1); } list->cfg.what_to_count |= COUNT_COUNTERS; @@ -422,6 +436,7 @@ if (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; + list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if (list->cfg.nfacctd_bgp && list->cfg.nfacctd_net == NF_NET_BGP) { list->cfg.what_to_count |= COUNT_SRC_NMASK; @@ -432,13 +447,18 @@ list->cfg.what_to_count |= COUNT_ID2; } if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); + COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| + COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| + COUNT_IS_SYMMETRIC)) { + Log(LOG_ERR, "ERROR: 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); exit(1); } +#if defined (HAVE_L2) + list->cfg.what_to_count |= COUNT_VLAN; + list->cfg.what_to_count |= COUNT_COS; +#endif + list->cfg.data_type = PIPE_TYPE_PAYLOAD; } else { diff -Nru pmacct-0.12.1/src/pmacct-defines.h pmacct-0.12.5/src/pmacct-defines.h --- pmacct-0.12.1/src/pmacct-defines.h 2010-04-06 17:00:52.000000000 +0000 +++ pmacct-0.12.5/src/pmacct-defines.h 2010-12-28 16:25:46.000000000 +0000 @@ -20,18 +20,20 @@ */ /* defines */ -#define ARGS_NFACCTD "n:dDhP:b:f:F:c:m:p:r:s:S:L:l:v:o:R" -#define ARGS_SFACCTD "n:dDhP:b:f:F:c:m:p:r:s:S:L:l:v:o:R" -#define ARGS_PMACCTD "n:NdDhP:b:f:F:c:i:I:m:p:r:s:S:v:o:wWL:R" -#define ARGS_UACCTD "n:NdDhP:b:f:F:c:m:p:r:s:S:v:o:Rg:L:" +#define ARGS_NFACCTD "n:dDhP:b:f:F:c:m:p:r:s:S:L:l:v:o:O:R" +#define ARGS_SFACCTD "n:dDhP:b:f:F:c:m:p:r:s:S:L:l:v:o:O:R" +#define ARGS_PMACCTD "n:NdDhP:b:f:F:c:i:I:m:p:r:s:S:v:o:O:wWL:R" +#define ARGS_UACCTD "n:NdDhP:b:f:F:c:m:p:r:s:S:v:o:O:Rg:L:" #define ARGS_PMACCT "Ssc:Cetm:p:P:M:arN:n:lT:" -#define N_PRIMITIVES 46 +#define N_PRIMITIVES 47 #define N_FUNCS 10 #define MAX_N_PLUGINS 32 #define PROTO_LEN 12 -#define MAX_MAP_ENTRIES 128 +#define MAX_MAP_ENTRIES 2048 /* allow maps */ +#define BGP_MD5_MAP_ENTRIES 8192 #define AGG_FILTER_ENTRIES 128 #define FOLLOW_BGP_NH_ENTRIES 32 +#define MAX_PROTOCOL_LEN 16 #define UINT32T_THRESHOLD 4290000000UL #define UINT64T_THRESHOLD 18446744073709551360ULL #ifndef UINT8_MAX @@ -56,13 +58,13 @@ #define LARGEBUFLEN (8192+MOREBUFSZ) #define MANTAINER "Paolo Lucente " -#define PMACCTD_USAGE_HEADER "Promiscuous Mode Accounting Daemon, pmacctd 0.12.1" -#define UACCTD_USAGE_HEADER "Linux NetFilter ULOG Accounting Daemon, pmacctd 0.12.1" -#define PMACCT_USAGE_HEADER "pmacct, pmacct client 0.12.1" -#define PMMYPLAY_USAGE_HEADER "pmmyplay, pmacct MySQL logfile player 0.12.1" -#define PMPGPLAY_USAGE_HEADER "pmpgplay, pmacct PGSQL logfile player 0.12.1" -#define NFACCTD_USAGE_HEADER "NetFlow Accounting Daemon, nfacctd 0.12.1" -#define SFACCTD_USAGE_HEADER "sFlow Accounting Daemon, sfacctd 0.12.1" +#define PMACCTD_USAGE_HEADER "Promiscuous Mode Accounting Daemon, pmacctd 0.12.5" +#define UACCTD_USAGE_HEADER "Linux NetFilter ULOG Accounting Daemon, pmacctd 0.12.5" +#define PMACCT_USAGE_HEADER "pmacct, pmacct client 0.12.5" +#define PMMYPLAY_USAGE_HEADER "pmmyplay, pmacct MySQL logfile player 0.12.5" +#define PMPGPLAY_USAGE_HEADER "pmpgplay, pmacct PGSQL logfile player 0.12.5" +#define NFACCTD_USAGE_HEADER "NetFlow Accounting Daemon, nfacctd 0.12.5" +#define SFACCTD_USAGE_HEADER "sFlow Accounting Daemon, sfacctd 0.12.5" #ifndef TRUE #define TRUE 1 @@ -95,7 +97,7 @@ #define MAP_BGP_SRC_MED 103 /* bgp_src_med_map */ #define MAP_BGP_IS_SYMMETRIC 104 /* bgp_is_symmetric_map */ -/* 44 primitives currently defined */ +/* 47 primitives currently defined */ #define COUNT_SRC_HOST 0x0000000000000001ULL #define COUNT_DST_HOST 0x0000000000000002ULL #define COUNT_SUM_HOST 0x0000000000000004ULL @@ -142,6 +144,7 @@ #define COUNT_OUT_IFACE 0x0000080000000000ULL #define COUNT_SRC_NMASK 0x0000100000000000ULL #define COUNT_DST_NMASK 0x0000200000000000ULL +#define COUNT_COS 0x0000400000000000ULL /* BYTES and PACKETS are used into templates; we let their values to overlap with some values we will not need into templates */ @@ -182,6 +185,7 @@ #define PIPE_TYPE_PAYLOAD 0x00000002 #define PIPE_TYPE_EXTRAS 0x00000004 #define PIPE_TYPE_BGP 0x00000008 +#define PIPE_TYPE_MSG 0x00000010 #define CHLD_WARNING 0x00000001 #define CHLD_ALERT 0x00000002 @@ -189,6 +193,19 @@ #define BGP_SRC_PRIMITIVES_MAP 0x00000001 #define BGP_SRC_PRIMITIVES_BGP 0x00000002 +#define PRINT_OUTPUT_FORMATTED 0x00000001 +#define PRINT_OUTPUT_CSV 0x00000002 + +#define DIRECTION_UNKNOWN 0x00000000 +#define DIRECTION_IN 0x00000001 +#define DIRECTION_OUT 0x00000002 +#define DIRECTION_TAG 0x00000004 +#define DIRECTION_TAG2 0x00000008 + +#define IFINDEX_STATIC 0x00000001 +#define IFINDEX_TAG 0x00000002 +#define IFINDEX_TAG2 0x00000004 + typedef u_int32_t pm_class_t; typedef u_int32_t pm_id_t; diff -Nru pmacct-0.12.1/src/pmacct.h pmacct-0.12.5/src/pmacct.h --- pmacct-0.12.1/src/pmacct.h 2010-03-09 11:56:46.000000000 +0000 +++ pmacct-0.12.5/src/pmacct.h 2010-06-25 16:48:05.000000000 +0000 @@ -287,7 +287,7 @@ #define EXT #endif EXT struct host_addr mcast_groups[MAX_MCAST_GROUPS]; -EXT int reload_map; +EXT int reload_map, reload_map_bgp_thread, data_plugins, tee_plugins; EXT struct child_ctl sql_writers; #undef EXT diff -Nru pmacct-0.12.1/src/pretag.c pmacct-0.12.5/src/pretag.c --- pmacct-0.12.1/src/pretag.c 2010-01-26 17:32:48.000000000 +0000 +++ pmacct-0.12.5/src/pretag.c 2010-05-12 17:11:26.000000000 +0000 @@ -162,13 +162,24 @@ key = NULL; value = NULL; } else { - for (dindex = 0; strcmp(tag_map_dictionary[dindex].key, ""); dindex++) { - if (!strcmp(tag_map_dictionary[dindex].key, key)) { - err = (*tag_map_dictionary[dindex].func)(filename, &tmp.e[tmp.num], value, req, acct_type); - break; + if (tee_plugins) { + for (dindex = 0; strcmp(tag_map_tee_dictionary[dindex].key, ""); dindex++) { + if (!strcmp(tag_map_tee_dictionary[dindex].key, key)) { + err = (*tag_map_tee_dictionary[dindex].func)(filename, &tmp.e[tmp.num], value, req, acct_type); + break; + } + else err = E_NOTFOUND; /* key not found */ } - else err = E_NOTFOUND; /* key not found */ - } + } + else { + for (dindex = 0; strcmp(tag_map_dictionary[dindex].key, ""); dindex++) { + if (!strcmp(tag_map_dictionary[dindex].key, key)) { + err = (*tag_map_dictionary[dindex].func)(filename, &tmp.e[tmp.num], value, req, acct_type); + break; + } + else err = E_NOTFOUND; /* key not found */ + } + } if (err) { if (err == E_NOTFOUND) Log(LOG_ERR, "ERROR ( %s ): unknown key '%s' at line %d. Ignored.\n", filename, key, tot_lines); else Log(LOG_ERR, "Line %d ignored.\n", tot_lines); diff -Nru pmacct-0.12.1/src/pretag-data.h pmacct-0.12.5/src/pretag-data.h --- pmacct-0.12.1/src/pretag-data.h 2010-01-29 18:02:58.000000000 +0000 +++ pmacct-0.12.5/src/pretag-data.h 2010-05-12 17:11:26.000000000 +0000 @@ -49,6 +49,17 @@ {"", NULL} }; +const struct _map_dictionary_line tag_map_tee_dictionary[] = { + {"id", PT_map_id_handler}, + {"id2", PT_map_id2_handler}, + {"ip", PT_map_ip_handler}, + {"label", PT_map_label_handler}, + {"jeq", PT_map_jeq_handler}, + {"return", PT_map_return_handler}, + {"stack", PT_map_stack_handler}, + {"", NULL} +}; + const struct _map_dictionary_line bpas_map_dictionary[] = { {"id", PT_map_id_handler}, {"ip", PT_map_ip_handler}, diff -Nru pmacct-0.12.1/src/pretag_handlers.c pmacct-0.12.5/src/pretag_handlers.c --- pmacct-0.12.1/src/pretag_handlers.c 2010-02-09 14:18:54.000000000 +0000 +++ pmacct-0.12.5/src/pretag_handlers.c 2010-08-07 13:56:47.000000000 +0000 @@ -848,14 +848,16 @@ { struct id_entry *entry = e; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; int ret = -1; - /* bgp_follow_nexthop hook */ - if (pptrs->bgp_nexthop) dst_ret = (struct bgp_node *) pptrs->bgp_nexthop; - if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + if (pptrs->bgp_nexthop_info) + info = (struct bgp_info *) pptrs->bgp_nexthop_info; + else + info = (struct bgp_info *) pptrs->bgp_dst_info; + if (info && info->attr) { if (info->attr->mp_nexthop.family == AF_INET) { ret = memcmp(&entry->bgp_nexthop.a.address.ipv4, &info->attr->mp_nexthop.address.ipv4, 4); @@ -1008,11 +1010,12 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; as_t asn = 0; if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (info->attr->aspath) { asn = evaluate_last_asn(info->attr->aspath); @@ -1080,11 +1083,12 @@ { struct id_entry *entry = e; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; as_t asn = 0; if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { if (info->attr->aspath) { asn = evaluate_last_asn(info->attr->aspath); @@ -1100,6 +1104,7 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; as_t asn = 0; @@ -1108,7 +1113,7 @@ } else if (config.nfacctd_bgp_peer_as_src_type == BGP_SRC_PRIMITIVES_BGP) { if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (info->attr->aspath && info->attr->aspath->str) { asn = evaluate_first_asn(info->attr->aspath->str); @@ -1125,11 +1130,12 @@ { struct id_entry *entry = e; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; as_t asn = 0; if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { if (info->attr->aspath && info->attr->aspath->str) { asn = evaluate_first_asn(info->attr->aspath->str); @@ -1145,6 +1151,7 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; u_int32_t local_pref = 0; @@ -1153,7 +1160,7 @@ } else if (config.nfacctd_bgp_src_local_pref_type == BGP_SRC_PRIMITIVES_BGP) { if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { local_pref = info->attr->local_pref; } @@ -1168,11 +1175,12 @@ { struct id_entry *entry = e; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; u_int32_t local_pref = 0; if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr) { local_pref = info->attr->local_pref; } @@ -1186,13 +1194,14 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; char tmp_stdcomms[MAX_BGP_STD_COMMS]; memset(tmp_stdcomms, 0, sizeof(tmp_stdcomms)); if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr && info->attr->community && info->attr->community->str) { evaluate_comm_patterns(tmp_stdcomms, info->attr->community->str, entry->src_comms, MAX_BGP_STD_COMMS); } @@ -1206,13 +1215,14 @@ { struct id_entry *entry = e; struct bgp_node *dst_ret = (struct bgp_node *) pptrs->bgp_dst; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; char tmp_stdcomms[MAX_BGP_STD_COMMS]; memset(tmp_stdcomms, 0, sizeof(tmp_stdcomms)); if (dst_ret) { - info = (struct bgp_info *) dst_ret->info; + info = (struct bgp_info *) pptrs->bgp_dst_info; if (info && info->attr && info->attr->community && info->attr->community->str) { evaluate_comm_patterns(tmp_stdcomms, info->attr->community->str, entry->comms, MAX_BGP_STD_COMMS); } @@ -1270,10 +1280,12 @@ if (!entry->id && entry->flags == BPAS_MAP_RCODE_BGP) { struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; + if (info && info->attr) { if (info->attr->aspath && info->attr->aspath->str) { *tid = evaluate_first_asn(info->attr->aspath->str); @@ -1433,10 +1445,11 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (entry->bgp_nexthop.a.family == AF_INET) { if (info->attr->mp_nexthop.family == AF_INET) { @@ -1464,11 +1477,12 @@ { struct id_entry *entry = e; struct bgp_node *src_ret = (struct bgp_node *) pptrs->bgp_src; + struct bgp_peer *peer = (struct bgp_peer *) pptrs->bgp_peer; struct bgp_info *info; as_t asn = 0; if (src_ret) { - info = (struct bgp_info *) src_ret->info; + info = (struct bgp_info *) pptrs->bgp_src_info; if (info && info->attr) { if (info->attr->aspath && info->attr->aspath->str) { asn = evaluate_first_asn(info->attr->aspath->str); diff -Nru pmacct-0.12.1/src/print_plugin.c pmacct-0.12.5/src/print_plugin.c --- pmacct-0.12.1/src/print_plugin.c 2009-12-25 22:01:08.000000000 +0000 +++ pmacct-0.12.5/src/print_plugin.c 2010-09-30 16:58:57.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -74,6 +74,9 @@ if (!config.print_refresh_time) config.print_refresh_time = DEFAULT_PRINT_REFRESH_TIME; + if (!config.print_output) + config.print_output = PRINT_OUTPUT_FORMATTED; + timeout = config.print_refresh_time*1000; if (config.what_to_count & (COUNT_SUM_HOST|COUNT_SUM_NET)) @@ -139,7 +142,10 @@ memset(sa.base, 0, sa.size); memset(&flushtime, 0, sizeof(flushtime)); - P_write_stats_header(); + if (config.print_output == PRINT_OUTPUT_FORMATTED) + P_write_stats_header_formatted(); + else if (config.print_output == PRINT_OUTPUT_CSV) + P_write_stats_header_csv(); /* plugin main loop */ for(;;) { @@ -457,87 +463,157 @@ if (!queue[j]->bytes_counter && !queue[j]->packet_counter && !queue[j]->flow_counter) continue; - printf("%-10u ", data->id); - printf("%-10u ", data->id2); - printf("%-16s ", ((data->class && class[(data->class)-1].id) ? class[(data->class)-1].protocol : "unknown" )); + if (config.print_output == PRINT_OUTPUT_FORMATTED) { + printf("%-10u ", data->id); + printf("%-10u ", data->id2); + printf("%-16s ", ((data->class && class[(data->class)-1].id) ? class[(data->class)-1].protocol : "unknown" )); + printf("%-10u ", data->ifindex_in); + printf("%-10u ", data->ifindex_out); #if defined (HAVE_L2) - etheraddr_string(data->eth_shost, src_mac); - printf("%-17s ", src_mac); - etheraddr_string(data->eth_dhost, dst_mac); - printf("%-17s ", dst_mac); - printf("%-5d ", data->vlan_id); -#endif - printf("%-10d ", data->src_as); - printf("%-10d ", data->dst_as); - printf("%-22s ", pbgp->std_comms); - - as_path = pbgp->as_path; - while (as_path) { - as_path = strchr(pbgp->as_path, ' '); - if (as_path) *as_path = '_'; - } - if (strlen(pbgp->as_path)) - printf("%-22s ", pbgp->as_path); - else - printf("%-22s ", empty_aspath); - - printf("%-5d ", pbgp->local_pref); - printf("%-5d ", pbgp->med); - printf("%-10d ", pbgp->peer_src_as); - printf("%-10d ", pbgp->peer_dst_as); - addr_to_str(ip_address, &pbgp->peer_src_ip); + etheraddr_string(data->eth_shost, src_mac); + printf("%-17s ", src_mac); + etheraddr_string(data->eth_dhost, dst_mac); + printf("%-17s ", dst_mac); + printf("%-5u ", data->vlan_id); + printf("%-2u ", data->cos); +#endif + printf("%-10u ", data->src_as); + printf("%-10u ", data->dst_as); + printf("%-22s ", pbgp->std_comms); + + as_path = pbgp->as_path; + while (as_path) { + as_path = strchr(pbgp->as_path, ' '); + if (as_path) *as_path = '_'; + } + if (strlen(pbgp->as_path)) + printf("%-22s ", pbgp->as_path); + else + printf("%-22s ", empty_aspath); + + printf("%-5u ", pbgp->local_pref); + printf("%-5u ", pbgp->med); + printf("%-10u ", pbgp->peer_src_as); + printf("%-10u ", pbgp->peer_dst_as); + addr_to_str(ip_address, &pbgp->peer_src_ip); #if defined ENABLE_IPV6 - printf("%-45s ", ip_address); + printf("%-45s ", ip_address); #else - printf("%-15s ", ip_address); + printf("%-15s ", ip_address); #endif - addr_to_str(ip_address, &pbgp->peer_dst_ip); + addr_to_str(ip_address, &pbgp->peer_dst_ip); #if defined ENABLE_IPV6 - printf("%-45s ", ip_address); + printf("%-45s ", ip_address); #else - printf("%-15s ", ip_address); + printf("%-15s ", ip_address); #endif - addr_to_str(src_host, &data->src_ip); + addr_to_str(src_host, &data->src_ip); #if defined ENABLE_IPV6 - printf("%-45s ", src_host); + printf("%-45s ", src_host); #else - printf("%-15s ", src_host); + printf("%-15s ", src_host); #endif - addr_to_str(dst_host, &data->dst_ip); + addr_to_str(dst_host, &data->dst_ip); #if defined ENABLE_IPV6 - printf("%-45s ", dst_host); + printf("%-45s ", dst_host); +#else + printf("%-15s ", dst_host); +#endif + printf("%-3u ", data->src_nmask); + printf("%-3u ", data->dst_nmask); + printf("%-5u ", data->src_port); + printf("%-5u ", data->dst_port); + printf("%-3u ", queue[j]->tcp_flags); + printf("%-10s ", _protocols[data->proto].name); + printf("%-3u ", data->tos); +#if defined HAVE_64BIT_COUNTERS + printf("%-20llu ", queue[j]->packet_counter); + printf("%-20llu ", queue[j]->flow_counter); + printf("%llu\n", queue[j]->bytes_counter); #else - printf("%-15s ", dst_host); + printf("%-10lu ", queue[j]->packet_counter); + printf("%-10lu ", queue[j]->flow_counter); + printf("%lu\n", queue[j]->bytes_counter); #endif - printf("%-5d ", data->src_port); - printf("%-5d ", data->dst_port); - printf("%-3d ", queue[j]->tcp_flags); - printf("%-10s ", _protocols[data->proto].name); - printf("%-3d ", data->tos); + } + else if (config.print_output == PRINT_OUTPUT_CSV) { + printf("%u,", data->id); + printf("%u,", data->id2); + printf("%s,", ((data->class && class[(data->class)-1].id) ? class[(data->class)-1].protocol : "unknown" )); + printf("%u,", data->ifindex_in); + printf("%u,", data->ifindex_out); +#if defined (HAVE_L2) + etheraddr_string(data->eth_shost, src_mac); + printf("%s,", src_mac); + etheraddr_string(data->eth_dhost, dst_mac); + printf("%s,", dst_mac); + printf("%u,", data->vlan_id); + printf("%u,", data->cos); +#endif + printf("%u,", data->src_as); + printf("%u,", data->dst_as); + printf("%s,", pbgp->std_comms); + + as_path = pbgp->as_path; + while (as_path) { + as_path = strchr(pbgp->as_path, ' '); + if (as_path) *as_path = '_'; + } + if (strlen(pbgp->as_path)) + printf("%s,", pbgp->as_path); + else + printf("%s,", empty_aspath); + + printf("%u,", pbgp->local_pref); + printf("%u,", pbgp->med); + printf("%u,", pbgp->peer_src_as); + printf("%u,", pbgp->peer_dst_as); + + addr_to_str(ip_address, &pbgp->peer_src_ip); + printf("%s,", ip_address); + addr_to_str(ip_address, &pbgp->peer_dst_ip); + printf("%s,", ip_address); + + addr_to_str(src_host, &data->src_ip); + printf("%s,", src_host); + addr_to_str(dst_host, &data->dst_ip); + printf("%s,", dst_host); + + printf("%u,", data->src_nmask); + printf("%u,", data->dst_nmask); + printf("%u,", data->src_port); + printf("%u,", data->dst_port); + printf("%u,", queue[j]->tcp_flags); + printf("%s,", _protocols[data->proto].name); + printf("%u,", data->tos); #if defined HAVE_64BIT_COUNTERS - printf("%-20llu ", queue[j]->packet_counter); - printf("%-20llu ", queue[j]->flow_counter); - printf("%llu\n", queue[j]->bytes_counter); + printf("%llu,", queue[j]->packet_counter); + printf("%llu,", queue[j]->flow_counter); + printf("%llu\n", queue[j]->bytes_counter); #else - printf("%-10lu ", queue[j]->packet_counter); - printf("%-10lu ", queue[j]->flow_counter); - printf("%lu\n", queue[j]->bytes_counter); + printf("%lu,", queue[j]->packet_counter); + printf("%lu,", queue[j]->flow_counter); + printf("%lu\n", queue[j]->bytes_counter); #endif + } } if (config.print_markers) printf("--END--\n"); } -void P_write_stats_header() +void P_write_stats_header_formatted() { printf("TAG "); printf("TAG2 "); printf("CLASS "); + printf("IN_IFACE "); + printf("OUT_IFACE "); #if defined HAVE_L2 printf("SRC_MAC "); printf("DST_MAC "); printf("VLAN "); + printf("COS "); #endif printf("SRC_AS "); printf("DST_AS "); @@ -556,6 +632,8 @@ printf("SRC_IP "); printf("DST_IP "); #endif + printf("SRC_MASK "); + printf("DST_MASK "); printf("SRC_PORT "); printf("DST_PORT "); printf("TCP_FLAGS "); @@ -572,6 +650,39 @@ #endif } +void P_write_stats_header_csv() +{ + printf("TAG,"); + printf("TAG2,"); + printf("CLASS,"); +#if defined HAVE_L2 + printf("SRC_MAC,"); + printf("DST_MAC,"); + printf("VLAN,"); + printf("COS,"); +#endif + printf("SRC_AS,"); + printf("DST_AS,"); + printf("BGP_COMMS,"); + printf("AS_PATH,"); + printf("PREF,"); + printf("MED,"); + printf("PEER_SRC_AS,"); + printf("PEER_DST_AS,"); + printf("PEER_SRC_IP,"); + printf("PEER_DST_IP,"); + printf("SRC_IP,"); + printf("DST_IP,"); + printf("SRC_PORT,"); + printf("DST_PORT,"); + printf("TCP_FLAGS,"); + printf("PROTOCOL,"); + printf("TOS,"); + printf("PACKETS,"); + printf("FLOWS,"); + printf("BYTES\n"); +} + void P_sum_host_insert(struct pkt_data *data, struct pkt_bgp_primitives *pbgp) { struct in_addr ip; diff -Nru pmacct-0.12.1/src/print_plugin.h pmacct-0.12.5/src/print_plugin.h --- pmacct-0.12.1/src/print_plugin.h 2009-09-18 16:21:29.000000000 +0000 +++ pmacct-0.12.5/src/print_plugin.h 2010-05-23 10:09:02.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -61,7 +61,8 @@ void P_cache_insert(struct pkt_data *, struct pkt_bgp_primitives *); void P_cache_flush(struct chained_cache *[], int); void P_cache_purge(struct chained_cache *[], int); -void P_write_stats_header(); +void P_write_stats_header_formatted(); +void P_write_stats_header_csv(); void P_exit_now(int); /* global vars */ diff -Nru pmacct-0.12.1/src/server.c pmacct-0.12.5/src/server.c --- pmacct-0.12.1/src/server.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/server.c 2010-10-31 22:51:41.000000000 +0000 @@ -105,7 +105,7 @@ q->what_to_count = config.what_to_count; for (idx = 0; idx < config.buckets; idx++) { if (!following_chain) acc_elem = (struct acc *) elem; - if (acc_elem->packet_counter && !acc_elem->reset_flag) { + if (acc_elem->bytes_counter && !acc_elem->reset_flag) { enQueue_elem(sd, &rb, acc_elem, PdataSz, PdataSz+PbgpSz); /* XXX: to be optimized ? */ if (PbgpSz) { @@ -142,7 +142,7 @@ do { if (following_chain) acc_elem = acc_elem->next; - if (acc_elem->packet_counter && !acc_elem->reset_flag) bd.howmany++; + if (acc_elem->bytes_counter && !acc_elem->reset_flag) bd.howmany++; bd.num = idx; /* we need to avoid this redundancy */ following_chain = TRUE; } while (acc_elem->next != NULL); @@ -162,7 +162,7 @@ if (request.what_to_count == config.what_to_count) { acc_elem = search_accounting_structure(&request.data, &request.pbgp); if (acc_elem) { - if (acc_elem->packet_counter && !acc_elem->reset_flag) { + if (acc_elem->bytes_counter && !acc_elem->reset_flag) { enQueue_elem(sd, &rb, acc_elem, PdataSz, PdataSz+PbgpSz); /* XXX: to be optimized ? */ if (PbgpSz) { @@ -203,7 +203,7 @@ for (idx = 0; idx < config.buckets; idx++) { if (!following_chain) acc_elem = (struct acc *) elem; - if (acc_elem->packet_counter && !acc_elem->reset_flag) { + if (acc_elem->bytes_counter && !acc_elem->reset_flag) { mask_elem(&tbuf, &bbuf, acc_elem, request.what_to_count); if (!memcmp(&tbuf, &request.data, sizeof(struct pkt_primitives)) && !memcmp(&bbuf, &request.pbgp, sizeof(struct pkt_bgp_primitives))) { @@ -244,7 +244,8 @@ /* XXX: we should try using pmct_get_max_entries() */ q->num = config.classifier_table_num; - if (!q->num && config.classifiers_path) q->num = MAX_CLASSIFIERS; + // if (!q->num && config.classifiers_path) q->num = MAX_CLASSIFIERS; + if (!q->num && class) q->num = MAX_CLASSIFIERS; while (idx < q->num) { enQueue_elem(sd, &rb, &class[idx], sizeof(struct stripped_class), sizeof(struct stripped_class)); @@ -273,6 +274,7 @@ if (w & COUNT_SRC_MAC) memcpy(d1->eth_shost, s1->eth_shost, ETH_ADDR_LEN); if (w & COUNT_DST_MAC) memcpy(d1->eth_dhost, s1->eth_dhost, ETH_ADDR_LEN); if (w & COUNT_VLAN) d1->vlan_id = s1->vlan_id; + if (w & COUNT_COS) d1->cos = s1->cos; #endif if (w & (COUNT_SRC_HOST|COUNT_SRC_NET)) { if (s1->src_ip.family == AF_INET) d1->src_ip.address.ipv4.s_addr = s1->src_ip.address.ipv4.s_addr; diff -Nru pmacct-0.12.1/src/sfacctd.c pmacct-0.12.5/src/sfacctd.c --- pmacct-0.12.1/src/sfacctd.c 2010-03-06 12:10:16.000000000 +0000 +++ pmacct-0.12.5/src/sfacctd.c 2010-10-28 07:52:42.000000000 +0000 @@ -61,23 +61,26 @@ printf(" -L \tBind to the specified IP address\n"); printf(" -l \tListen on the specified UDP port\n"); printf(" -f \tLoad configuration from the specified file\n"); - printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | none] \n\tAggregation string (DEFAULT: src_host)\n"); + printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t tos | proto | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | cos | none ] \n\tAggregation string (DEFAULT: src_host)\n"); printf(" -D \tDaemonize\n"); printf(" -n \tPath to a file containing Network definitions\n"); printf(" -o \tPath to a file containing Port definitions\n"); - printf(" -P \t[ memory | print | mysql | pgsql | sqlite3 | nfprobe | sfprobe ] \n\tActivate plugin\n"); + printf(" -P \t[ memory | print | mysql | pgsql | sqlite3 | tee ] \n\tActivate plugin\n"); printf(" -d \tEnable debug\n"); printf(" -S \t[ auth | mail | daemon | kern | user | local[0-7] ] \n\ttLog to the specified syslog facility\n"); printf(" -F \tWrite Core Process PID into the specified file\n"); printf(" -R \tRenormalize sampled data\n"); - printf("\nMemory Plugin (-P memory) options:\n"); + printf("\nMemory plugin (-P memory) options:\n"); printf(" -p \tSocket for client-server communication (DEFAULT: /tmp/collect.pipe)\n"); printf(" -b \tNumber of buckets\n"); printf(" -m \tNumber of memory pools\n"); printf(" -s \tMemory pool size\n"); printf("\nPostgreSQL (-P pgsql)/MySQL (-P mysql)/SQLite (-P sqlite3) plugin options:\n"); printf(" -r \tRefresh time (in seconds)\n"); - printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] \n\tTable version\n"); + printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] \n\tTable version\n"); + printf("\nPrint plugin (-P print) plugin options:\n"); + printf(" -r \tRefresh time (in seconds)\n"); + printf(" -O \t[ formatted | csv ] \n\tOutput format\n"); printf("\n"); printf(" See EXAMPLES or visit http://wiki.pmacct.net/ for examples.\n"); printf("\n"); @@ -153,6 +156,8 @@ bta_map_allocated = FALSE; find_id_func = SF_find_id; + data_plugins = 0; + tee_plugins = 0; xflow_status_table_entries = 0; xflow_tot_bad_datagrams = 0; errflag = 0; @@ -217,6 +222,11 @@ strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; + case 'O': + strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN); + strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); + rows++; + break; case 'f': strlcpy(config_file, optarg, sizeof(config_file)); break; @@ -349,77 +359,15 @@ Log(LOG_ERR, "ERROR: Internal packet sampling and external packet sampling are mutual exclusive.\n"); exit(1); } - if (list->type.id == PLUGIN_ID_NFPROBE) { - /* If we already renormalizing an external sampling rate, - we cancel the sampling information from the probe plugin */ - if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; - - list->cfg.nfprobe_what_to_count = list->cfg.what_to_count; - list->cfg.what_to_count = 0; -#if defined (HAVE_L2) - if (list->cfg.nfprobe_version == 9) { - list->cfg.what_to_count |= COUNT_SRC_MAC; - list->cfg.what_to_count |= COUNT_DST_MAC; - list->cfg.what_to_count |= COUNT_VLAN; - } -#endif - list->cfg.what_to_count |= COUNT_SRC_HOST; - list->cfg.what_to_count |= COUNT_DST_HOST; - - if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) { - list->cfg.what_to_count |= COUNT_SRC_NMASK; - list->cfg.what_to_count |= COUNT_DST_NMASK; - } - - list->cfg.what_to_count |= COUNT_SRC_PORT; - list->cfg.what_to_count |= COUNT_DST_PORT; - list->cfg.what_to_count |= COUNT_IP_TOS; - list->cfg.what_to_count |= COUNT_IP_PROTO; - if (list->cfg.networks_file || list->cfg.nfacctd_as == NF_AS_KEEP || - list->cfg.nfacctd_as == NF_AS_BGP) { - list->cfg.what_to_count |= COUNT_SRC_AS; - list->cfg.what_to_count |= COUNT_DST_AS; - } - if (list->cfg.nfprobe_version == 9 && list->cfg.classifiers_path) - list->cfg.what_to_count |= COUNT_CLASS; - if (list->cfg.nfprobe_version == 9 && list->cfg.pre_tag_map) { - list->cfg.what_to_count |= COUNT_ID; - list->cfg.what_to_count |= COUNT_ID2; - } - list->cfg.what_to_count |= COUNT_IN_IFACE; - list->cfg.what_to_count |= COUNT_OUT_IFACE; - if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); - exit(1); - } - list->cfg.what_to_count |= COUNT_COUNTERS; - list->cfg.data_type = PIPE_TYPE_METADATA; - list->cfg.data_type |= PIPE_TYPE_EXTRAS; + if (list->type.id == PLUGIN_ID_NFPROBE || list->type.id == PLUGIN_ID_SFPROBE) { + Log(LOG_ERR, "ERROR: 'nfprobe' and 'sfprobe' plugins not supported in 'sfacctd'.\n"); + exit(1); } - else if (list->type.id == PLUGIN_ID_SFPROBE) { - /* If we already renormalizing an external sampling rate, - we cancel the sampling information from the probe plugin */ - if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; - - list->cfg.what_to_count = COUNT_PAYLOAD; - if (list->cfg.classifiers_path) list->cfg.what_to_count |= COUNT_CLASS; - if (list->cfg.pre_tag_map) { - list->cfg.what_to_count |= COUNT_ID; - list->cfg.what_to_count |= COUNT_ID2; - } - if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); - exit(1); - } - - list->cfg.data_type = PIPE_TYPE_PAYLOAD; + else if (list->type.id == PLUGIN_ID_TEE) { + tee_plugins++; + list->cfg.what_to_count = COUNT_NONE; + list->cfg.data_type = PIPE_TYPE_MSG; } else { list->cfg.data_type = PIPE_TYPE_METADATA; @@ -440,10 +388,7 @@ if (!list->cfg.nfacctd_net) { if (list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; if (list->cfg.networks_mask) list->cfg.nfacctd_net |= NF_NET_STATIC; - if (!list->cfg.nfacctd_net) { - Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'sfacctd_net', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string); - exit(1); - } + if (!list->cfg.nfacctd_net) list->cfg.nfacctd_net = NF_NET_KEEP; } else { if ((list->cfg.nfacctd_net == NF_NET_NEW && !list->cfg.networks_file) || @@ -461,12 +406,18 @@ bgp_config_checks(&list->cfg); + data_plugins++; list->cfg.what_to_count |= COUNT_COUNTERS; } } list = list->next; } + if (tee_plugins && data_plugins) { + Log(LOG_ERR, "ERROR: 'tee' plugins are not compatible with data (memory/mysql/pgsql/etc.) plugins. Exiting...\n\n"); + exit(1); + } + /* signal handling we want to inherit to plugins (when not re-defined elsewhere) */ signal(SIGCHLD, startup_handle_falling_child); /* takes note of plugins failed during startup phase */ signal(SIGHUP, reload); /* handles reopening of syslog channel */ @@ -792,8 +743,8 @@ for (;;) { // memset(&spp, 0, sizeof(spp)); ret = recvfrom(config.sock, sflow_packet, SFLOW_MAX_MSG_SIZE, 0, (struct sockaddr *) &client, &clen); - spp.rawSample = sflow_packet; - spp.rawSampleLen = ret; + spp.rawSample = pptrs.v4.f_header = sflow_packet; + spp.rawSampleLen = pptrs.v4.f_len = ret; spp.datap = (u_int32_t *) spp.rawSample; spp.endp = sflow_packet + spp.rawSampleLen; reset_tag_status(&pptrs); @@ -822,20 +773,25 @@ reload_map = FALSE; } - switch(spp.datagramVersion = getData32(&spp)) { - case 5: - getAddress(&spp, &spp.agent_addr); - process_SFv5_packet(&spp, &pptrs, &req, (struct sockaddr *) &client); - break; - case 4: - case 2: - getAddress(&spp, &spp.agent_addr); - process_SFv2v4_packet(&spp, &pptrs, &req, (struct sockaddr *) &client); - break; - default: - notify_malf_packet(LOG_INFO, "INFO: Discarding unknown packet", (struct sockaddr *) pptrs.v4.f_agent); - xflow_tot_bad_datagrams++; - break; + if (data_plugins) { + switch(spp.datagramVersion = getData32(&spp)) { + case 5: + getAddress(&spp, &spp.agent_addr); + process_SFv5_packet(&spp, &pptrs, &req, (struct sockaddr *) &client); + break; + case 4: + case 2: + getAddress(&spp, &spp.agent_addr); + process_SFv2v4_packet(&spp, &pptrs, &req, (struct sockaddr *) &client); + break; + default: + notify_malf_packet(LOG_INFO, "INFO: Discarding unknown packet", (struct sockaddr *) pptrs.v4.f_agent); + xflow_tot_bad_datagrams++; + break; + } + } + else if (tee_plugins) { + process_SF_raw_packet(&spp, &pptrs, &req, (struct sockaddr *) &client); } } } @@ -919,6 +875,44 @@ } } +void process_SF_raw_packet(SFSample *spp, struct packet_ptrs_vector *pptrsv, + struct plugin_requests *req, struct sockaddr *agent) +{ + struct packet_ptrs *pptrs = &pptrsv->v4; + + switch(spp->datagramVersion = getData32(spp)) { + case 5: + getAddress(spp, &spp->agent_addr); + spp->agentSubId = getData32(spp); + pptrs->seqno = getData32(spp); + break; + case 4: + case 2: + getAddress(spp, &spp->agent_addr); + spp->agentSubId = 0; /* not supported */ + pptrs->seqno = getData32(spp); + break; + default: + notify_malf_packet(LOG_INFO, "INFO: Discarding unknown sFlow packet", (struct sockaddr *) pptrs->f_agent); + xflow_tot_bad_datagrams++; + return; + } + + if (config.debug) { + struct host_addr a; + u_char agent_addr[50]; + u_int16_t agent_port; + + sa_to_addr((struct sockaddr *)pptrs->f_agent, &a, &agent_port); + addr_to_str(agent_addr, &a); + + Log(LOG_DEBUG, "DEBUG ( default/core ): Received sFlow packet from [%s:%u] version [%u] seqno [%u]\n", agent_addr, agent_port, spp->datagramVersion, pptrs->seqno); + } + + if (config.pre_tag_map) SF_find_id((struct id_table *)pptrs->idtable, pptrs, &pptrs->tag, &pptrs->tag2); + exec_plugins(pptrs); +} + void compute_once() { struct pkt_data dummy; @@ -926,6 +920,7 @@ CounterSz = sizeof(dummy.pkt_len); PdataSz = sizeof(struct pkt_data); PpayloadSz = sizeof(struct pkt_payload); + PmsgSz = sizeof(struct pkt_msg); PextrasSz = sizeof(struct pkt_extras); PbgpSz = sizeof(struct pkt_bgp_primitives); ChBufHdrSz = sizeof(struct ch_buf_hdr); @@ -938,6 +933,7 @@ PptrsSz = sizeof(struct packet_ptrs); CSSz = sizeof(struct class_st); HostAddrSz = sizeof(struct host_addr); + UDPHdrSz = sizeof(struct my_udphdr); #if defined ENABLE_IPV6 IP6HdrSz = sizeof(struct ip6_hdr); @@ -1023,7 +1019,8 @@ /* | pri | c | vlan-id | */ /* ------------------------------------- */ /* [priority = 3bits] [Canonical Format Flag = 1bit] [vlan-id = 12 bits] */ - sample->in_vlan = vlan; + if (!sample->in_vlan && !sample->out_vlan) sample->in_vlan = vlan; + if (!sample->in_priority && !sample->out_priority) sample->in_priority = priority; sample->eth_type = (ptr[0] << 8) + ptr[1]; ptr += 2; @@ -1597,7 +1594,7 @@ memcpy(bufptr, &ret, 4); bufptr += 4; - sample->class = NF_evaluate_classifiers(buf); + sample->class = SF_evaluate_classifiers(buf); } else skipBytes(sample, MAX_PROTOCOL_LEN); } @@ -1897,8 +1894,8 @@ outp = getData32(sample); sample->inputPortFormat = inp >> 30; sample->outputPortFormat = outp >> 30; - sample->inputPort = inp & 0x3fffffff; - sample->outputPort = outp & 0x3fffffff; + sample->inputPort = inp; // skip 0x3fffffff mask + sample->outputPort = outp; // skip 0x3fffffff mask } num_elements = getData32(sample); @@ -1992,9 +1989,13 @@ struct packet_ptrs *pptrs = &pptrsv->v4; u_int16_t dcd_sport = htons(sample->dcd_sport), dcd_dport = htons(sample->dcd_dport); u_int8_t dcd_ipProtocol = sample->dcd_ipProtocol, dcd_ipTos = sample->dcd_ipTos; - u_int16_t in_vlan = htons(sample->in_vlan); + u_int8_t dcd_tcpFlags = sample->dcd_tcpFlags; + u_int16_t vlan = htons(sample->in_vlan); u_int16_t flow_type; + /* check for out_vlan */ + if (!vlan && sample->out_vlan) vlan = htons(sample->out_vlan); + /* We consider packets if: - sample->gotIPV4 || sample->gotIPV6 : it belongs to either an IPv4 or IPv6 packet. @@ -2019,6 +2020,7 @@ memcpy(&((struct my_iphdr *)pptrs->iph_ptr)->ip_tos, &dcd_ipTos, 1); memcpy(&((struct my_tlhdr *)pptrs->tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrs->tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrs->tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrs->l4_proto = sample->dcd_ipProtocol; @@ -2044,8 +2046,9 @@ memcpy(&((struct ip6_hdr *)pptrsv->v6.iph_ptr)->ip6_dst, &sample->ipdst.address.ip_v6, IP6AddrSz); memcpy(&((struct ip6_hdr *)pptrsv->v6.iph_ptr)->ip6_nxt, &dcd_ipProtocol, 1); /* XXX: class ID ? */ - memcpy(&((struct my_tlhdr *)pptrsv->v6.tlh_ptr)->src_port, &dcd_sport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->v6.tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrsv->v6.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->v6.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->v6.l4_proto = sample->dcd_ipProtocol; @@ -2066,7 +2069,7 @@ memcpy(pptrsv->vlan4.mac_ptr+ETH_ADDR_LEN, &sample->eth_src, ETH_ADDR_LEN); memcpy(pptrsv->vlan4.mac_ptr, &sample->eth_dst, ETH_ADDR_LEN); - memcpy(pptrsv->vlan4.vlan_ptr, &in_vlan, 2); + memcpy(pptrsv->vlan4.vlan_ptr, &vlan, 2); ((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_vhl = 0x45; memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_src, &sample->dcd_srcIP, 4); memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_dst, &sample->dcd_dstIP, 4); @@ -2074,6 +2077,7 @@ memcpy(&((struct my_iphdr *)pptrsv->vlan4.iph_ptr)->ip_tos, &dcd_ipTos, 1); memcpy(&((struct my_tlhdr *)pptrsv->vlan4.tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrsv->vlan4.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->vlan4.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->vlan4.l4_proto = sample->dcd_ipProtocol; @@ -2094,14 +2098,15 @@ memcpy(pptrsv->vlan6.mac_ptr+ETH_ADDR_LEN, &sample->eth_src, ETH_ADDR_LEN); memcpy(pptrsv->vlan6.mac_ptr, &sample->eth_dst, ETH_ADDR_LEN); - memcpy(pptrsv->vlan6.vlan_ptr, &in_vlan, 2); + memcpy(pptrsv->vlan6.vlan_ptr, &vlan, 2); ((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_ctlun.ip6_un2_vfc = 0x60; memcpy(&((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_src, &sample->ipsrc.address.ip_v6, IP6AddrSz); memcpy(&((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_dst, &sample->ipdst.address.ip_v6, IP6AddrSz); memcpy(&((struct ip6_hdr *)pptrsv->vlan6.iph_ptr)->ip6_nxt, &dcd_ipProtocol, 1); /* XXX: class ID ? */ - memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->src_port, &dcd_sport, 2); - memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->src_port, &dcd_sport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->vlan6.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->vlan6.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->vlan6.l4_proto = sample->dcd_ipProtocol; @@ -2141,8 +2146,9 @@ memcpy(&((struct my_iphdr *)pptrsv->mpls4.iph_ptr)->ip_dst, &sample->dcd_dstIP, 4); memcpy(&((struct my_iphdr *)pptrsv->mpls4.iph_ptr)->ip_p, &dcd_ipProtocol, 1); memcpy(&((struct my_iphdr *)pptrsv->mpls4.iph_ptr)->ip_tos, &dcd_ipTos, 1); - memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->src_port, &dcd_sport, 2); - memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->src_port, &dcd_sport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->mpls4.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->mpls4.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->mpls4.l4_proto = sample->dcd_ipProtocol; @@ -2181,8 +2187,9 @@ memcpy(&((struct ip6_hdr *)pptrsv->mpls6.iph_ptr)->ip6_dst, &sample->ipdst.address.ip_v6, IP6AddrSz); memcpy(&((struct ip6_hdr *)pptrsv->mpls6.iph_ptr)->ip6_nxt, &dcd_ipProtocol, 1); /* XXX: class ID ? */ - memcpy(&((struct my_tlhdr *)pptrsv->mpls6.tlh_ptr)->src_port, &dcd_sport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->mpls6.tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrsv->mpls6.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->mpls6.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->mpls6.l4_proto = sample->dcd_ipProtocol; @@ -2205,7 +2212,7 @@ reset_mac_vlan(&pptrsv->vlanmpls4); memcpy(pptrsv->vlanmpls4.mac_ptr+ETH_ADDR_LEN, &sample->eth_src, ETH_ADDR_LEN); memcpy(pptrsv->vlanmpls4.mac_ptr, &sample->eth_dst, ETH_ADDR_LEN); - memcpy(pptrsv->vlanmpls4.vlan_ptr, &in_vlan, 2); + memcpy(pptrsv->vlanmpls4.vlan_ptr, &vlan, 2); for (idx = 0; idx <= sample->lstk.depth && idx < 10; idx++) { label = sample->lstk.stack[idx]; @@ -2224,6 +2231,7 @@ memcpy(&((struct my_iphdr *)pptrsv->vlanmpls4.iph_ptr)->ip_tos, &dcd_ipTos, 1); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls4.tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls4.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->vlanmpls4.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->vlanmpls4.l4_proto = sample->dcd_ipProtocol; @@ -2246,7 +2254,7 @@ reset_mac_vlan(&pptrsv->vlanmpls6); memcpy(pptrsv->vlanmpls6.mac_ptr+ETH_ADDR_LEN, &sample->eth_src, ETH_ADDR_LEN); memcpy(pptrsv->vlanmpls6.mac_ptr, &sample->eth_dst, ETH_ADDR_LEN); - memcpy(pptrsv->vlanmpls6.vlan_ptr, &in_vlan, 2); + memcpy(pptrsv->vlanmpls6.vlan_ptr, &vlan, 2); for (idx = 0; idx <= sample->lstk.depth && idx < 10; idx++) { label = sample->lstk.stack[idx]; @@ -2263,8 +2271,9 @@ memcpy(&((struct ip6_hdr *)pptrsv->vlanmpls6.iph_ptr)->ip6_dst, &sample->ipdst.address.ip_v6, IP6AddrSz); memcpy(&((struct ip6_hdr *)pptrsv->vlanmpls6.iph_ptr)->ip6_nxt, &dcd_ipProtocol, 1); /* XXX: class ID ? */ - memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls6.tlh_ptr)->src_port, &dcd_sport, 2); + memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls6.tlh_ptr)->src_port, &dcd_sport, 2); memcpy(&((struct my_tlhdr *)pptrsv->vlanmpls6.tlh_ptr)->dst_port, &dcd_dport, 2); + memcpy(&((struct my_tcphdr *)pptrsv->vlanmpls6.tlh_ptr)->th_flags, &dcd_tcpFlags, 1); } pptrsv->vlanmpls6.l4_proto = sample->dcd_ipProtocol; @@ -2369,7 +2378,7 @@ SFSample *sample = (SFSample *)pptrs->f_data; u_int8_t ret = 0; - if (sample->in_vlan) ret += NF9_FTYPE_VLAN; + if (sample->in_vlan || sample->out_vlan) ret += NF9_FTYPE_VLAN; if (sample->lstk.depth > 0) ret += NF9_FTYPE_MPLS; if (sample->gotIPV4); else if (sample->gotIPV6) ret += NF9_FTYPE_IPV6; diff -Nru pmacct-0.12.1/src/sfacctd.h pmacct-0.12.5/src/sfacctd.h --- pmacct-0.12.1/src/sfacctd.h 2009-12-29 00:15:37.000000000 +0000 +++ pmacct-0.12.5/src/sfacctd.h 2010-05-12 17:11:26.000000000 +0000 @@ -279,6 +279,7 @@ EXT void process_SFv2v4_packet(SFSample *, struct packet_ptrs_vector *, struct plugin_requests *, struct sockaddr *); EXT void process_SFv5_packet(SFSample *, struct packet_ptrs_vector *, struct plugin_requests *, struct sockaddr *); +EXT void process_SF_raw_packet(SFSample *, struct packet_ptrs_vector *, struct plugin_requests *, struct sockaddr *); EXT void readv2v4FlowSample(SFSample *, struct packet_ptrs_vector *, struct plugin_requests *); EXT void readv5FlowSample(SFSample *, int, struct packet_ptrs_vector *, struct plugin_requests *); EXT void readv2v4CountersSample(SFSample *); diff -Nru pmacct-0.12.1/src/sfprobe_plugin/sflow_agent.c pmacct-0.12.5/src/sfprobe_plugin/sflow_agent.c --- pmacct-0.12.1/src/sfprobe_plugin/sflow_agent.c 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/src/sfprobe_plugin/sflow_agent.c 2010-06-09 16:04:13.000000000 +0000 @@ -49,6 +49,21 @@ if((agent->receiverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) sfl_agent_sysError(agent, "agent", "socket open failed"); } + + if (config.nfprobe_ipprec) { + int opt = config.nfprobe_ipprec << 5; + int rc; + + rc = setsockopt(agent->receiverSocket, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)); + if (rc < 0) Log(LOG_WARNING, "WARN ( %s/%s ): setsockopt() failed for IP_TOS: %s\n", config.name, config.type, strerror(errno)); + } + + if (config.pipe_size) { + int rc; + + rc = Setsocksize(agent->receiverSocket, SOL_SOCKET, SO_SNDBUF, &config.pipe_size, sizeof(config.pipe_size)); + if (rc < 0) Log(LOG_WARNING, "WARN ( %s/%s ): setsockopt() failed for SOL_SNDBUF: %s\n", config.name, config.type, strerror(errno)); + } } /*_________________---------------------------__________________ diff -Nru pmacct-0.12.1/src/sfprobe_plugin/sflow_api.h pmacct-0.12.5/src/sfprobe_plugin/sflow_api.h --- pmacct-0.12.1/src/sfprobe_plugin/sflow_api.h 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/src/sfprobe_plugin/sflow_api.h 2010-07-25 23:25:24.000000000 +0000 @@ -261,7 +261,7 @@ /* software sampling: call this with every packet - returns non-zero if the packet should be sampled (in which case you then call sfl_sampler_writeFlowSample()) */ -int sfl_sampler_takeSample(SFLSampler *sampler, u_int32_t); +int sfl_sampler_takeSample(SFLSampler *sampler); /* call this to set a maximum samples-per-second threshold. If the sampler reaches this threshold it will automatically back off the sampling rate. A value of 0 disables the diff -Nru pmacct-0.12.1/src/sfprobe_plugin/sflow_sampler.c pmacct-0.12.5/src/sfprobe_plugin/sflow_sampler.c --- pmacct-0.12.1/src/sfprobe_plugin/sflow_sampler.c 2006-11-19 15:16:07.000000000 +0000 +++ pmacct-0.12.5/src/sfprobe_plugin/sflow_sampler.c 2010-07-25 23:25:24.000000000 +0000 @@ -158,12 +158,34 @@ -----------------___________________________------------------ */ +int sfl_sampler_takeSample(SFLSampler *sampler) +{ + if (sampler->skip == 0) { + /* first time - seed the random number generator */ + srandom(SFL_DS_INDEX(sampler->dsi)); + sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate); + } + + // increment the samplePool + sampler->samplePool++; + + if (--sampler->skip == 0) { + /* reached zero. Set the next skip and return true. */ + sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate); + return 1; + } + + return 0; +} + +/* int sfl_sampler_takeSample(SFLSampler *sampler, u_int32_t pkts) { sampler->samplePool++; return pkts; } +*/ /* int sfl_sampler_takeSample(SFLSampler *sampler, u_int32_t pkts) @@ -192,24 +214,3 @@ return sampledPkts; } */ - -/* -int sfl_sampler_takeSample(SFLSampler *sampler, u_int32_t pkts) -{ - if(sampler->skip == 0) { - // first time - seed the random number generator - srandom(SFL_DS_INDEX(sampler->dsi)); - sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate); - } - - // increment the samplePool - sampler->samplePool++; - - if(--sampler->skip == 0) { - // reached zero. Set the next skip and return true. - sampler->skip = nextRandomSkip(sampler->sFlowFsPacketSamplingRate); - return 1; - } - return 0; -} -*/ diff -Nru pmacct-0.12.1/src/sfprobe_plugin/sfprobe_plugin.c pmacct-0.12.5/src/sfprobe_plugin/sfprobe_plugin.c --- pmacct-0.12.1/src/sfprobe_plugin/sfprobe_plugin.c 2010-03-17 18:17:38.000000000 +0000 +++ pmacct-0.12.5/src/sfprobe_plugin/sfprobe_plugin.c 2010-07-28 17:40:36.000000000 +0000 @@ -23,10 +23,22 @@ #include "net_aggr.h" #include "ports_aggr.h" +#define SFL_DIRECTION_IN 0 +#define SFL_DIRECTION_OUT 1 +#define SFL_MAX_INTERFACES 4096 + +typedef struct _SflSp_counters { + u_int32_t ifIndex; + u_int32_t frames[2]; + u_int64_t bytes[2]; + u_int32_t multicasts[2]; + u_int32_t broadcasts[2]; +} SflSp_counters; + typedef struct _SflSp { int verbose; char *device; - u_int32_t ifIndex; + int ifIndex_Type; int ifType; u_int64_t ifSpeed; int ifDirection; @@ -40,22 +52,14 @@ int batch; pcap_t *pcap; - // counters for each direction -#define SFL_DIRECTION_IN 0 -#define SFL_DIRECTION_OUT 1 - u_int32_t frames[2]; - u_int64_t bytes[2]; - u_int32_t multicasts[2]; - u_int32_t broadcasts[2]; + SflSp_counters counters[SFL_MAX_INTERFACES]; struct in_addr agentIP; u_int32_t agentSubId; struct in_addr interfaceIP; struct in6_addr interfaceIP6; - char interfaceMAC[6]; char pad[2]; - int gotInterfaceMAC; SFLAgent *agent; SFLSampler *sampler; @@ -104,7 +108,8 @@ static void setDefaults(SflSp *sp) { sp->device = NULL; - sp->ifIndex = 1; + sp->counters[0].ifIndex = 1; + sp->ifIndex_Type = IFINDEX_STATIC; sp->ifType = 6; // ethernet_csmacd sp->ifSpeed = 100000000L; // assume 100 MBit sp->ifDirection = 1; // assume full duplex @@ -142,34 +147,41 @@ void agentCB_getCounters(void *magic, SFLPoller *poller, SFL_COUNTERS_SAMPLE_TYPE *cs) { + SFLCounters_sample_element genElem[SFL_MAX_INTERFACES]; SflSp *sp = (SflSp *)magic; + int idx = 0; - // build a counters sample - SFLCounters_sample_element genElem; memset(&genElem, 0, sizeof(genElem)); - genElem.tag = SFLCOUNTERS_GENERIC; - // don't need to set the length here (set by the encoder) - genElem.counterBlock.generic.ifIndex = sp->ifIndex; - genElem.counterBlock.generic.ifType = sp->ifType; - genElem.counterBlock.generic.ifSpeed = sp->ifSpeed; - genElem.counterBlock.generic.ifDirection = sp->ifDirection; - genElem.counterBlock.generic.ifStatus = 0x03; // adminStatus = up, operStatus = up - genElem.counterBlock.generic.ifPromiscuousMode = sp->promiscuous; - // these counters would normally be a snapshot the hardware interface counters - the - // same ones that the SNMP agent uses to answer SNMP requests to the ifTable. To ease - // the portability of this program, however, I am just using some counters that were - // added up in software: - genElem.counterBlock.generic.ifInOctets = sp->bytes[SFL_DIRECTION_IN]; - genElem.counterBlock.generic.ifInUcastPkts = sp->frames[SFL_DIRECTION_IN]; - genElem.counterBlock.generic.ifInMulticastPkts = sp->multicasts[SFL_DIRECTION_IN]; - genElem.counterBlock.generic.ifInBroadcastPkts = sp->broadcasts[SFL_DIRECTION_IN]; - genElem.counterBlock.generic.ifOutOctets = sp->bytes[SFL_DIRECTION_OUT]; - genElem.counterBlock.generic.ifOutUcastPkts = sp->frames[SFL_DIRECTION_OUT]; - genElem.counterBlock.generic.ifOutMulticastPkts = sp->multicasts[SFL_DIRECTION_OUT]; - genElem.counterBlock.generic.ifOutBroadcastPkts = sp->broadcasts[SFL_DIRECTION_OUT]; - // add this counter block to the counter sample that we are building - SFLADD_ELEMENT(cs, &genElem); + // build a counters sample + for (idx = 0; idx < SFL_MAX_INTERFACES && sp->counters[idx].ifIndex; idx++) { + if (sp->counters[idx].frames[SFL_DIRECTION_IN] || + sp->counters[idx].frames[SFL_DIRECTION_OUT]) { + genElem[idx].tag = SFLCOUNTERS_GENERIC; + // don't need to set the length here (set by the encoder) + genElem[idx].counterBlock.generic.ifIndex = sp->counters[idx].ifIndex; + genElem[idx].counterBlock.generic.ifType = sp->ifType; + genElem[idx].counterBlock.generic.ifSpeed = sp->ifSpeed; + genElem[idx].counterBlock.generic.ifDirection = sp->ifDirection; + genElem[idx].counterBlock.generic.ifStatus = 0x03; // adminStatus = up, operStatus = up + genElem[idx].counterBlock.generic.ifPromiscuousMode = sp->promiscuous; + // these counters would normally be a snapshot the hardware interface counters - the + // same ones that the SNMP agent uses to answer SNMP requests to the ifTable. To ease + // the portability of this program, however, I am just using some counters that were + // added up in software: + genElem[idx].counterBlock.generic.ifInOctets = sp->counters[idx].bytes[SFL_DIRECTION_IN]; + genElem[idx].counterBlock.generic.ifInUcastPkts = sp->counters[idx].frames[SFL_DIRECTION_IN]; + genElem[idx].counterBlock.generic.ifInMulticastPkts = sp->counters[idx].multicasts[SFL_DIRECTION_IN]; + genElem[idx].counterBlock.generic.ifInBroadcastPkts = sp->counters[idx].broadcasts[SFL_DIRECTION_IN]; + genElem[idx].counterBlock.generic.ifOutOctets = sp->counters[idx].bytes[SFL_DIRECTION_OUT]; + genElem[idx].counterBlock.generic.ifOutUcastPkts = sp->counters[idx].frames[SFL_DIRECTION_OUT]; + genElem[idx].counterBlock.generic.ifOutMulticastPkts = sp->counters[idx].multicasts[SFL_DIRECTION_OUT]; + genElem[idx].counterBlock.generic.ifOutBroadcastPkts = sp->counters[idx].broadcasts[SFL_DIRECTION_OUT]; + + // add this counter block to the counter sample that we are building + SFLADD_ELEMENT(cs, &genElem[idx]); + } + } // pass these counters down to be encoded and included with the next sFlow datagram sfl_poller_writeCountersSample(poller, cs); @@ -253,10 +265,10 @@ static void readPacket(SflSp *sp, struct pkt_payload *hdr, const unsigned char *buf) { - SFLFlow_sample_element hdrElem, classHdrElem, gatewayHdrElem, routerHdrElem, tagHdrElem; + SFLFlow_sample_element hdrElem, classHdrElem, gatewayHdrElem, routerHdrElem, tagHdrElem, switchHdrElem; SFLExtended_as_path_segment as_path_segment; u_int32_t frame_len, header_len; - int direction, sampledPackets, ethHdrLen; + int direction, sampledPackets, ethHdrLen, idx = 0; struct eth_header dummy_eh; u_int16_t ethType = 0, cap_len = hdr->cap_len, pkt_len = hdr->pkt_len; unsigned char *local_buf = (unsigned char *) buf; @@ -290,115 +302,164 @@ pkt_len, cap_len); - // test the src mac address to know the direction. Anything with src = interfaceMAC - // will be counted as output, and everything else can be counted as input. (There may - // be a way to get this info from the pcap library, but I don't know the incantation. - // (If you know how to do that, please let me know). - direction = memcmp(sp->interfaceMAC, local_buf + 6, 6) ? SFL_DIRECTION_IN : SFL_DIRECTION_OUT; + /* Let's fill sample direction in - and default to ingress */ + direction = 0; + + if (config.nfprobe_direction) { + switch (config.nfprobe_direction) { + case DIRECTION_IN: + direction = SFL_DIRECTION_IN; + break; + case DIRECTION_OUT: + direction = SFL_DIRECTION_OUT; + break; + case DIRECTION_TAG: + if (hdr->tag == 1) direction = SFL_DIRECTION_IN; + else if (hdr->tag == 2) direction = SFL_DIRECTION_OUT; + break; + case DIRECTION_TAG2: + if (hdr->tag2 == 1) direction = SFL_DIRECTION_IN; + else if (hdr->tag2 == 2) direction = SFL_DIRECTION_OUT; + break; + } + } + + // Let's determine the ifIndex + if (!hdr->ifindex_in && !hdr->ifindex_out) { + if (sp->ifIndex_Type) { + switch (sp->ifIndex_Type) { + case IFINDEX_TAG: + for (idx = 0; idx < SFL_MAX_INTERFACES; idx++) { + if (sp->counters[idx].ifIndex == hdr->tag || idx == (SFL_MAX_INTERFACES-1)) break; + else if (sp->counters[idx].ifIndex == 0) { + sp->counters[idx].ifIndex = hdr->tag; + break; + } + } + break; + case IFINDEX_TAG2: + for (idx = 0; idx < SFL_MAX_INTERFACES; idx++) { + if (sp->counters[idx].ifIndex == hdr->tag2 || idx == (SFL_MAX_INTERFACES-1)) break; + else if (sp->counters[idx].ifIndex == 0) { + sp->counters[idx].ifIndex = hdr->tag2; + break; + } + } + break; + } + } + } + else { + u_int32_t ifIndex = (direction == SFL_DIRECTION_IN) ? hdr->ifindex_in : hdr->ifindex_out; + + for (idx = 0; idx < SFL_MAX_INTERFACES; idx++) { + if (sp->counters[idx].ifIndex == ifIndex || idx == (SFL_MAX_INTERFACES-1)) break; + else if (sp->counters[idx].ifIndex == 0) { + sp->counters[idx].ifIndex = ifIndex; + break; + } + } + } // maintain some counters in software - just to ease portability - sp->bytes[direction] += pkt_len; + sp->counters[idx].bytes[direction] += pkt_len; if (local_buf[0] & 0x01) { if(local_buf[0] == 0xff && local_buf[1] == 0xff && local_buf[2] == 0xff && local_buf[3] == 0xff && local_buf[4] == 0xff && - local_buf[5] == 0xff) sp->broadcasts[direction]++; - else sp->multicasts[direction]++; + local_buf[5] == 0xff) sp->counters[idx].broadcasts[direction]++; + else sp->counters[idx].multicasts[direction]++; } - else sp->frames[direction]++; + else sp->counters[idx].frames[direction]++; - // OLD: test to see if we want to sample this packet - { - sampledPackets = hdr->pkt_num; - sp->sampler->samplePool += hdr->sample_pool; - - /* In case of flows (ie. hdr->pkt_num > 1) we have now computed how - many packets to sample; let's cheat counters */ - if (sampledPackets > 1) { - pkt_len = pkt_len / hdr->pkt_num; - hdr->pkt_num = 1; - } - - while (sampledPackets > 0) { - // Yes. Build a flow sample and send it off... - SFL_FLOW_SAMPLE_TYPE fs; - memset(&fs, 0, sizeof(fs)); - - // Since we are an end host, we are not switching or routing - // this packet. On a switch or router this is just like a - // packet going to or from the management agent. That means - // the local interface index should be filled in as the special - // value 0x3FFFFFFF, which is defined in the sFlow spec as - // an "internal" interface. - if (!hdr->ifindex_in && !hdr->ifindex_out) { - fs.input = (direction == SFL_DIRECTION_IN) ? sp->ifIndex : 0x3FFFFFFF; - fs.output = (direction == SFL_DIRECTION_IN) ? 0x3FFFFFFF : sp->ifIndex; - } - else { - fs.input = (hdr->ifindex_in) ? hdr->ifindex_in : 0x3FFFFFFF; - fs.output = (hdr->ifindex_out) ? hdr->ifindex_out : 0x3FFFFFFF; - } - - memset(&hdrElem, 0, sizeof(hdrElem)); + if (config.ext_sampling_rate || sfl_sampler_takeSample(sp->sampler)) { + // Yes. Build a flow sample and send it off... + SFL_FLOW_SAMPLE_TYPE fs; + memset(&fs, 0, sizeof(fs)); + + if (!hdr->ifindex_in && !hdr->ifindex_out) { + if (sp->ifIndex_Type) { + switch (sp->ifIndex_Type) { + case IFINDEX_STATIC: + fs.input = (direction == SFL_DIRECTION_IN) ? sp->counters[0].ifIndex : 0x3FFFFFFF; + fs.output = (direction == SFL_DIRECTION_OUT) ? sp->counters[0].ifIndex : 0x3FFFFFFF; + break; + case IFINDEX_TAG: + fs.input = (direction == SFL_DIRECTION_IN) ? hdr->tag : 0x3FFFFFFF; + fs.output = (direction == SFL_DIRECTION_OUT) ? hdr->tag : 0x3FFFFFFF; + break; + case IFINDEX_TAG2: + fs.input = (direction == SFL_DIRECTION_IN) ? hdr->tag2 : 0x3FFFFFFF; + fs.output = (direction == SFL_DIRECTION_OUT) ? hdr->tag2 : 0x3FFFFFFF; + break; + } + } + } + else { + fs.input = (hdr->ifindex_in) ? hdr->ifindex_in : 0x3FFFFFFF; + fs.output = (hdr->ifindex_out) ? hdr->ifindex_out : 0x3FFFFFFF; + } + + memset(&hdrElem, 0, sizeof(hdrElem)); - hdrElem.tag = SFLFLOW_HEADER; + hdrElem.tag = SFLFLOW_HEADER; - if (!ethType) hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023; - else { - switch (ntohs(ethType)) { - case ETHERTYPE_IP: - hdrElem.flowType.header.header_protocol = SFLHEADER_IPv4; - break; - case ETHERTYPE_IPV6: - hdrElem.flowType.header.header_protocol = SFLHEADER_IPv6; - break; + if (!ethType) hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023; + else { + switch (ntohs(ethType)) { + case ETHERTYPE_IP: + hdrElem.flowType.header.header_protocol = SFLHEADER_IPv4; + break; + case ETHERTYPE_IPV6: + hdrElem.flowType.header.header_protocol = SFLHEADER_IPv6; + break; default: hdrElem.flowType.header.header_protocol = SFLHEADER_ETHERNET_ISO8023; break; - } } - - // the FCS trailing bytes should be counted in the frame_length - // but they should also be recorded in the "stripped" field. - // assume that libpcap is not giving us the FCS - frame_len = pkt_len; - if (config.acct_type == ACCT_PM) { - u_int32_t FCS_bytes = 4; - hdrElem.flowType.header.frame_length = frame_len + FCS_bytes; - hdrElem.flowType.header.stripped = FCS_bytes; - } - else hdrElem.flowType.header.frame_length = frame_len; + } + + // the FCS trailing bytes should be counted in the frame_length + // but they should also be recorded in the "stripped" field. + // assume that libpcap is not giving us the FCS + frame_len = pkt_len; + if (config.acct_type == ACCT_PM) { + u_int32_t FCS_bytes = 4; + hdrElem.flowType.header.frame_length = frame_len + FCS_bytes; + hdrElem.flowType.header.stripped = FCS_bytes; + } + else hdrElem.flowType.header.frame_length = frame_len; - header_len = cap_len; - if (header_len > frame_len) header_len = frame_len; - if (header_len > sp->snaplen) header_len = sp->snaplen; - hdrElem.flowType.header.header_length = header_len; - hdrElem.flowType.header.header_bytes = (u_int8_t *)local_buf; - SFLADD_ELEMENT(&fs, &hdrElem); + header_len = cap_len; + if (header_len > frame_len) header_len = frame_len; + if (header_len > sp->snaplen) header_len = sp->snaplen; + hdrElem.flowType.header.header_length = header_len; + hdrElem.flowType.header.header_bytes = (u_int8_t *)local_buf; + SFLADD_ELEMENT(&fs, &hdrElem); - if (config.what_to_count & COUNT_CLASS) { + if (config.what_to_count & COUNT_CLASS) { memset(&classHdrElem, 0, sizeof(classHdrElem)); classHdrElem.tag = SFLFLOW_EX_CLASS; classHdrElem.flowType.class.class = hdr->class; SFLADD_ELEMENT(&fs, &classHdrElem); - } + } - if (config.what_to_count & (COUNT_ID|COUNT_ID2)) { - memset(&tagHdrElem, 0, sizeof(tagHdrElem)); - tagHdrElem.tag = SFLFLOW_EX_TAG; - tagHdrElem.flowType.tag.tag = hdr->tag; - tagHdrElem.flowType.tag.tag2 = hdr->tag2; - SFLADD_ELEMENT(&fs, &tagHdrElem); - } + if (config.what_to_count & (COUNT_ID|COUNT_ID2)) { + memset(&tagHdrElem, 0, sizeof(tagHdrElem)); + tagHdrElem.tag = SFLFLOW_EX_TAG; + tagHdrElem.flowType.tag.tag = hdr->tag; + tagHdrElem.flowType.tag.tag2 = hdr->tag2; + SFLADD_ELEMENT(&fs, &tagHdrElem); + } - /* - Extended gateway is meant to have a broad range of - informations; we will fill in only infos pertaining + /* + Extended gateway is meant to have a broad range of + informations; we will fill in only infos pertaining to src and dst ASNs - */ - if (config.networks_file || config.nfacctd_as == NF_AS_BGP) { + */ + if (config.networks_file || config.nfacctd_as == NF_AS_BGP) { memset(&gatewayHdrElem, 0, sizeof(gatewayHdrElem)); memset(&as_path_segment, 0, sizeof(as_path_segment)); gatewayHdrElem.tag = SFLFLOW_EX_GATEWAY; @@ -409,22 +470,50 @@ as_path_segment.type = SFLEXTENDED_AS_SET; as_path_segment.length = 1; as_path_segment.as.set = &hdr->dst_as; + if (config.what_to_count & COUNT_PEER_DST_IP) { + switch (hdr->bgp_next_hop.family) { + case AF_INET: + gatewayHdrElem.flowType.gateway.nexthop.type = SFLADDRESSTYPE_IP_V4; + memcpy(&gatewayHdrElem.flowType.gateway.nexthop.address.ip_v4, &hdr->bgp_next_hop.address.ipv4, 4); + break; +#if defined ENABLE_IPV6 + case AF_INET6: + gatewayHdrElem.flowType.gateway.nexthop.type = SFLADDRESSTYPE_IP_V6; + memcpy(&gatewayHdrElem.flowType.gateway.nexthop.address.ip_v6, &hdr->bgp_next_hop.address.ipv6, 16); + break; +#endif + default: + memset(&gatewayHdrElem.flowType.gateway.nexthop, 0, sizeof(routerHdrElem.flowType.router.nexthop)); + break; + } + } SFLADD_ELEMENT(&fs, &gatewayHdrElem); - } + } - if (config.what_to_count & (COUNT_SRC_NMASK|COUNT_DST_NMASK)) { + if (config.what_to_count & (COUNT_SRC_NMASK|COUNT_DST_NMASK)) { memset(&routerHdrElem, 0, sizeof(routerHdrElem)); routerHdrElem.tag = SFLFLOW_EX_ROUTER; routerHdrElem.flowType.router.src_mask = hdr->src_nmask; routerHdrElem.flowType.router.dst_mask = hdr->dst_nmask; SFLADD_ELEMENT(&fs, &routerHdrElem); - } - - // submit the sample to be encoded and sent out - that's all there is to it(!) - sfl_sampler_writeFlowSample(sp->sampler, &fs); + } - sampledPackets--; + if (config.what_to_count & (COUNT_VLAN|COUNT_COS)) { + memset(&switchHdrElem, 0, sizeof(switchHdrElem)); + switchHdrElem.tag = SFLFLOW_EX_SWITCH; + if (direction == SFL_DIRECTION_IN) { + switchHdrElem.flowType.sw.src_vlan = hdr->vlan; + switchHdrElem.flowType.sw.src_priority = hdr->priority; + } + else if (direction == SFL_DIRECTION_OUT) { + switchHdrElem.flowType.sw.dst_vlan = hdr->vlan; + switchHdrElem.flowType.sw.dst_priority = hdr->priority; + } + SFLADD_ELEMENT(&fs, &switchHdrElem); } + + // submit the sample to be encoded and sent out - that's all there is to it(!) + sfl_sampler_writeFlowSample(sp->sampler, &fs); } } @@ -451,9 +540,9 @@ static void process_config_options(SflSp *sp) { - // sp->ifIndex = atoi(optarg); - // sp->ifSpeed = strtoll(optarg, NULL, 0); - + if (config.nfprobe_ifindex_type) sp->ifIndex_Type = config.nfprobe_ifindex_type; + if (config.nfprobe_ifindex) sp->counters[0].ifIndex = config.nfprobe_ifindex; + if (config.sfprobe_ifspeed) sp->ifSpeed = config.sfprobe_ifspeed; if (config.sfprobe_agentip) sp->agentIP.s_addr = Name_to_IP(config.sfprobe_agentip); if (config.sfprobe_agentsubid) sp->agentSubId = config.sfprobe_agentsubid; if (config.sfprobe_receiver) parse_receiver(config.sfprobe_receiver, &sp->collectorIP, &sp->collectorPort); @@ -513,9 +602,6 @@ setDefaults(&sp); process_config_options(&sp); - // remember if we got a mac address, so we can use it to infer direction - // sp.gotInterfaceMAC = ((getDevFlags & GETDEV_FOUND_MAC) != 0); - // create the agent and sampler objects init_agent(&sp); diff -Nru pmacct-0.12.1/src/signals.c pmacct-0.12.5/src/signals.c --- pmacct-0.12.1/src/signals.c 2009-10-18 13:50:19.000000000 +0000 +++ pmacct-0.12.5/src/signals.c 2010-06-25 16:48:06.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -176,8 +176,12 @@ void reload_maps() { reload_map = FALSE; + reload_map_bgp_thread = FALSE; - if (config.refresh_maps) reload_map = TRUE; + if (config.refresh_maps) { + reload_map = TRUE; + reload_map_bgp_thread = TRUE; + } signal(SIGUSR2, reload_maps); } diff -Nru pmacct-0.12.1/src/sql_common.c pmacct-0.12.5/src/sql_common.c --- pmacct-0.12.1/src/sql_common.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/sql_common.c 2010-11-27 11:09:29.000000000 +0000 @@ -140,7 +140,10 @@ /* PbgpSz is non-zero if at least one of the BGP-related primitives is enabled. This helps putting ASNs in the right field */ - if (PbgpSz) config.sql_table_version += SQL_TABLE_VERSION_BGP; + if (PbgpSz) { + config.sql_table_version += SQL_TABLE_VERSION_BGP; + Log(LOG_INFO, "INFO ( %s/%s ): sql_table_type set to 'bgp' (aggregate includes one or more BGP primitives).\n", config.name, config.type); + } } qq_ptr = 0; @@ -351,7 +354,8 @@ /* If we are very near to our maximum writers threshold, let's resort to any configured recovery mechanism - SQL_CACHE_COMMITTED => SQL_CACHE_ERROR; otherwise, will proceed as usual */ - if (sql_writers.active == config.sql_max_writers-1) { + if ((sql_writers.active == config.sql_max_writers-1) && + (config.sql_backup_host || config.sql_recovery_logfile)) { for (j = 0; j < index; j++) { if (queue[j]->valid == SQL_CACHE_COMMITTED) queue[j]->valid = SQL_CACHE_ERROR; } @@ -1011,6 +1015,20 @@ primitive++; } } + + if (what_to_count & COUNT_COS) { + if (primitive) { + strncat(insert_clause, ", ", SPACELEFT(insert_clause)); + strncat(values[primitive].string, ", ", sizeof(values[primitive].string)); + strncat(where[primitive].string, " AND ", sizeof(where[primitive].string)); + } + strncat(insert_clause, "cos", SPACELEFT(insert_clause)); + strncat(values[primitive].string, "%u", SPACELEFT(values[primitive].string)); + strncat(where[primitive].string, "cos=%u", SPACELEFT(where[primitive].string)); + values[primitive].type = where[primitive].type = COUNT_COS; + values[primitive].handler = where[primitive].handler = count_cos_handler; + primitive++; + } #endif if (what_to_count & (COUNT_SRC_HOST|COUNT_SRC_NET|COUNT_SUM_HOST|COUNT_SUM_NET)) { @@ -1478,7 +1496,7 @@ strncat(values[primitive].string, ", ", sizeof(values[primitive].string)); strncat(where[primitive].string, " AND ", sizeof(where[primitive].string)); } - if (!strcmp(config.type, "mysql") || !strcmp(config.type, "sqlite3")) { + if ((!strcmp(config.type, "mysql") || !strcmp(config.type, "sqlite3")) && config.sql_table_version != 8) { strncat(insert_clause, "src_port", SPACELEFT(insert_clause)); strncat(where[primitive].string, "src_port=%u", SPACELEFT(where[primitive].string)); } @@ -1511,7 +1529,7 @@ strncat(values[primitive].string, ", ", sizeof(values[primitive].string)); strncat(where[primitive].string, " AND ", sizeof(where[primitive].string)); } - if (!strcmp(config.type, "mysql") || !strcmp(config.type, "sqlite3")) { + if ((!strcmp(config.type, "mysql") || !strcmp(config.type, "sqlite3")) && config.sql_table_version != 8) { strncat(insert_clause, "dst_port", SPACELEFT(insert_clause)); strncat(where[primitive].string, "dst_port=%u", SPACELEFT(where[primitive].string)); } @@ -2104,13 +2122,13 @@ void sql_create_table(struct DBdesc *db, struct insert_data *idata) { struct tm *nowtm; - char buf[LONGLONGSRVBUFLEN], tmpbuf[LONGLONGSRVBUFLEN]; + char buf[LARGEBUFLEN], tmpbuf[LARGEBUFLEN]; int ret; - ret = read_SQLquery_from_file(config.sql_table_schema, tmpbuf, LONGLONGSRVBUFLEN); + ret = read_SQLquery_from_file(config.sql_table_schema, tmpbuf, LARGEBUFLEN); if (ret) { nowtm = localtime(&idata->basetime); - strftime(buf, LONGLONGSRVBUFLEN, tmpbuf, nowtm); + strftime(buf, LARGEBUFLEN, tmpbuf, nowtm); (*sqlfunc_cbr.create_table)(db, buf); } } diff -Nru pmacct-0.12.1/src/sql_common.h pmacct-0.12.5/src/sql_common.h --- pmacct-0.12.1/src/sql_common.h 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/sql_common.h 2010-06-07 01:21:57.000000000 +0000 @@ -199,6 +199,7 @@ EXT void count_src_mac_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); EXT void count_dst_mac_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); EXT void count_vlan_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); +EXT void count_cos_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); EXT void count_src_host_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); EXT void count_src_as_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); EXT void count_dst_host_handler(const struct db_cache *, const struct insert_data *, int, char **, char **); diff -Nru pmacct-0.12.1/src/sql_handlers.c pmacct-0.12.5/src/sql_handlers.c --- pmacct-0.12.1/src/sql_handlers.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/sql_handlers.c 2010-06-07 01:21:57.000000000 +0000 @@ -78,6 +78,14 @@ *ptr_where += strlen(*ptr_where); *ptr_values += strlen(*ptr_values); } + +void count_cos_handler(const struct db_cache *cache_elem, const struct insert_data *idata, int num, char **ptr_values, char **ptr_where) +{ + snprintf(*ptr_where, SPACELEFT(where_clause), where[num].string, cache_elem->primitives.cos); + snprintf(*ptr_values, SPACELEFT(values_clause), values[num].string, cache_elem->primitives.cos); + *ptr_where += strlen(*ptr_where); + *ptr_values += strlen(*ptr_values); +} #endif void count_src_host_handler(const struct db_cache *cache_elem, const struct insert_data *idata, int num, char **ptr_values, char **ptr_where) diff -Nru pmacct-0.12.1/src/sqlite3_plugin.c pmacct-0.12.5/src/sqlite3_plugin.c --- pmacct-0.12.1/src/sqlite3_plugin.c 2010-03-05 17:44:50.000000000 +0000 +++ pmacct-0.12.5/src/sqlite3_plugin.c 2010-10-06 07:26:12.000000000 +0000 @@ -640,6 +640,7 @@ if (!config.sql_db) config.sql_db = sqlite3_db; if (!config.sql_table) { if (config.sql_table_version == (SQL_TABLE_VERSION_BGP+1)) config.sql_table = sqlite3_table_bgp; + else if (config.sql_table_version == 8) config.sql_table = sqlite3_table_v8; else if (config.sql_table_version == 7) config.sql_table = sqlite3_table_v7; else if (config.sql_table_version == 6) config.sql_table = sqlite3_table_v6; else if (config.sql_table_version == 5) config.sql_table = sqlite3_table_v5; diff -Nru pmacct-0.12.1/src/sqlite3_plugin.h pmacct-0.12.5/src/sqlite3_plugin.h --- pmacct-0.12.1/src/sqlite3_plugin.h 2009-07-14 16:26:13.000000000 +0000 +++ pmacct-0.12.5/src/sqlite3_plugin.h 2010-10-06 07:26:12.000000000 +0000 @@ -47,4 +47,5 @@ static char sqlite3_table_v5[] = "acct_v5"; static char sqlite3_table_v6[] = "acct_v6"; static char sqlite3_table_v7[] = "acct_v7"; +static char sqlite3_table_v8[] = "acct_v8"; static char sqlite3_table_bgp[] = "acct_bgp"; diff -Nru pmacct-0.12.1/src/tee_plugin/Makefile.in pmacct-0.12.5/src/tee_plugin/Makefile.in --- pmacct-0.12.1/src/tee_plugin/Makefile.in 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/src/tee_plugin/Makefile.in 2010-05-04 11:20:38.000000000 +0000 @@ -0,0 +1,44 @@ +# $Id: Makefile.in,v 1.1 2010/05/04 11:20:38 paolo Exp $ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ +sbindir=@sbindir@ +libexecdir=@libexecdir@ +datadir=@datadir@ +mandir=@mandir@ +sysconfdir=@sysconfdir@ +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +VPATH=@srcdir@ +CC=@CC@ +DEFS=@DEFS@ +LDFLAGS=@LDFLAGS@ +CFLAGS=$(DEFS) -I$(srcdir) -I.. @CFLAGS@ +CPPFLAGS=@CPPFLAGS@ +LIBS=@LIBS@ +INSTALL=@INSTALL@ +RANLIB=@RANLIB@ + +TARGETS=libtee_plugin.a + +all: $(TARGETS) + +libtee_plugin.a: tee_plugin.o + ar rc $@ tee_plugin.o + $(RANLIB) $@ + +clean: + rm -f $(TARGETS) *.o core *.core + +realclean: clean + rm -rf autom4te.cache Makefile config.log config.status + +distclean: realclean + rm -f config.h* configure + +strip: + strip $(TARGETS) + +install: all + diff -Nru pmacct-0.12.1/src/tee_plugin/tee_plugin.c pmacct-0.12.5/src/tee_plugin/tee_plugin.c --- pmacct-0.12.1/src/tee_plugin/tee_plugin.c 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/src/tee_plugin/tee_plugin.c 2010-05-13 17:30:42.000000000 +0000 @@ -0,0 +1,342 @@ +/* + pmacct (Promiscuous mode IP Accounting package) + pmacct is Copyright (C) 2003-2010 by Paolo Lucente +*/ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#define __TEE_PLUGIN_C + +#include "../pmacct.h" +#include "tee_plugin.h" +#include "pmacct-data.h" +#include "plugin_hooks.h" + +void tee_plugin(int pipe_fd, struct configuration *cfgptr, void *ptr) +{ + struct pkt_msg *msg; + unsigned char *pipebuf; + struct pollfd pfd; + int timeout, err; + int ret, num, fd; + struct ring *rg = &((struct channels_list_entry *)ptr)->rg; + struct ch_status *status = ((struct channels_list_entry *)ptr)->status; + u_int32_t bufsz = ((struct channels_list_entry *)ptr)->bufsize; + char *dataptr, dest_addr[256], dest_serv[256]; + + struct sockaddr dest; + socklen_t dest_len; + + unsigned char *rgptr; + int pollagain = TRUE; + u_int32_t seq = 1, rg_err_count = 0; + + /* XXX: glue */ + memcpy(&config, cfgptr, sizeof(struct configuration)); + recollect_pipe_memory(ptr); + pm_setproctitle("%s [%s]", "Tee Plugin", config.name); + if (config.pidfile) write_pid_file_plugin(config.pidfile, config.type, config.name); + + /* signal handling */ + signal(SIGINT, Tee_exit_now); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + signal(SIGPIPE, SIG_IGN); +#if !defined FBSD4 + signal(SIGCHLD, SIG_IGN); +#else + signal(SIGCHLD, ignore_falling_child); +#endif + + if (config.tee_transparent && getuid() != 0) { + Log(LOG_ERR, "ERROR ( %s/%s ): Transparent mode requires super-user permissions. Exiting ...\n", config.name, config.type); + exit_plugin(1); + } + + if (!config.nfprobe_receiver) { + Log(LOG_ERR, "ERROR ( %s/%s ): tee_receiver is not specified. Exiting ...\n", config.name, config.type); + exit_plugin(1); + } + + memset(&dest, 0, sizeof(dest)); + dest_len = sizeof(dest); + Tee_parse_hostport(config.nfprobe_receiver, (struct sockaddr *)&dest, &dest_len); + + config.print_refresh_time = DEFAULT_TEE_REFRESH_TIME; + timeout = config.print_refresh_time*1000; + + pipebuf = (unsigned char *) Malloc(config.buffer_size); + + pfd.fd = pipe_fd; + pfd.events = POLLIN; + setnonblocking(pipe_fd); + + memset(pipebuf, 0, config.buffer_size); + + /* Arrange send socket */ + if (dest.sa_family != 0) { + if ((err = getnameinfo((struct sockaddr *) &dest, + dest_len, dest_addr, sizeof(dest_addr), + dest_serv, sizeof(dest_serv), NI_NUMERICHOST)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): getnameinfo: %d\n", config.name, config.type, err); + exit_plugin(1); + } + fd = Tee_prepare_sock(&dest, dest_len); + } + + /* plugin main loop */ + for (;;) { + poll_again: + status->wakeup = TRUE; + ret = poll(&pfd, 1, timeout); + if (ret < 0) goto poll_again; + + switch (ret) { + case 0: /* timeout */ + /* reserved for future since we don't currently cache/batch/etc */ + break; + default: /* we received data */ + read_data: + if (!pollagain) { + seq++; + seq %= MAX_SEQNUM; + if (seq == 0) rg_err_count = FALSE; + } + else { + if ((ret = read(pipe_fd, &rgptr, sizeof(rgptr))) == 0) + exit_plugin(1); /* we exit silently; something happened at the write end */ + } + + if (((struct ch_buf_hdr *)rg->ptr)->seq != seq) { + if (!pollagain) { + pollagain = TRUE; + goto poll_again; + } + else { + rg_err_count++; + if (config.debug || (rg_err_count > MAX_RG_COUNT_ERR)) { + Log(LOG_ERR, "ERROR ( %s/%s ): We are missing data.\n", config.name, config.type); + Log(LOG_ERR, "If you see this message once in a while, discard it. Otherwise some solutions follow:\n"); + Log(LOG_ERR, "- increase shared memory size, 'plugin_pipe_size'; now: '%u'.\n", config.pipe_size); + Log(LOG_ERR, "- increase buffer size, 'plugin_buffer_size'; now: '%u'.\n", config.buffer_size); + Log(LOG_ERR, "- increase system maximum socket size.\n\n"); + } + seq = ((struct ch_buf_hdr *)rg->ptr)->seq; + } + } + + pollagain = FALSE; + memcpy(pipebuf, rg->ptr, bufsz); + if ((rg->ptr+bufsz) >= rg->end) rg->ptr = rg->base; + else rg->ptr += bufsz; + + msg = (struct pkt_msg *) (pipebuf+sizeof(struct ch_buf_hdr)); + + while (((struct ch_buf_hdr *)pipebuf)->num) { + Tee_send(msg, &dest, fd); + + ((struct ch_buf_hdr *)pipebuf)->num--; + if (((struct ch_buf_hdr *)pipebuf)->num) { + dataptr = (unsigned char *) msg; + dataptr += PmsgSz; + msg = (struct pkt_msg *) dataptr; + } + } + goto read_data; + } + } +} + +void Tee_exit_now(int signum) +{ + wait(NULL); + exit_plugin(0); +} + +void Tee_send(struct pkt_msg *msg, struct sockaddr *target, int fd) +{ + if (config.debug) { + struct host_addr a; + u_char agent_addr[50]; + u_int16_t agent_port; + + sa_to_addr((struct sockaddr *)msg, &a, &agent_port); + addr_to_str(agent_addr, &a); + Log(LOG_DEBUG, "DEBUG ( %s/%s ): Sending NetFlow packet from [%s:%u] seqno [%u] to [%s]\n", + config.name, config.type, agent_addr, agent_port, msg->seqno, config.nfprobe_receiver); + } + + if (!config.tee_transparent) { + if (send(fd, msg->payload, msg->len, 0) == -1) + Log(LOG_ERR, "ERROR ( %s/%s ): send() to [%s] failed (%s)\n", config.name, config.type, config.nfprobe_receiver, strerror(errno)); + } + else { + char *buf_ptr = tee_send_buf; + struct sockaddr_in *sa = (struct sockaddr_in *) &msg->agent; + struct my_iphdr *i4h = (struct my_iphdr *) buf_ptr; +#if defined ENABLE_IPV6 + struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &msg->agent; + struct ip6_hdr *i6h = (struct ip6_hdr *) buf_ptr; +#endif + struct my_udphdr *uh; + + if (msg->agent.sa_family == target->sa_family) { + /* UDP header first */ + if (target->sa_family == AF_INET) { + buf_ptr += IP4HdrSz; + uh = (struct my_udphdr *) buf_ptr; + uh->uh_sport = sa->sin_port; + uh->uh_dport = ((struct sockaddr_in *)target)->sin_port; + } +#if defined ENABLE_IPV6 + else if (target->sa_family == AF_INET6) { + buf_ptr += IP6HdrSz; + uh = (struct my_udphdr *) buf_ptr; + uh->uh_sport = sa6->sin6_port; + uh->uh_dport = ((struct sockaddr_in6 *)target)->sin6_port; + } +#endif + + uh->uh_ulen = htons(msg->len+UDPHdrSz); + uh->uh_sum = 0; + + /* IP header then */ + if (target->sa_family == AF_INET) { + i4h->ip_vhl = 4; + i4h->ip_vhl <<= 4; + i4h->ip_vhl |= (IP4HdrSz/4); + i4h->ip_tos = 0; + i4h->ip_len = htons(IP4HdrSz+UDPHdrSz+msg->len); + i4h->ip_id = 0; + i4h->ip_off = 0; + i4h->ip_ttl = 255; + i4h->ip_p = IPPROTO_UDP; + i4h->ip_sum = 0; + i4h->ip_src.s_addr = sa->sin_addr.s_addr; + i4h->ip_dst.s_addr = ((struct sockaddr_in *)target)->sin_addr.s_addr; + } +#if defined ENABLE_IPV6 + else if (target->sa_family == AF_INET6) { + i6h->ip6_vfc = 6; + i6h->ip6_vfc <<= 4; + i6h->ip6_plen = htons(UDPHdrSz+msg->len); + i6h->ip6_nxt = IPPROTO_UDP; + i6h->ip6_hlim = 255; + memcpy(&i6h->ip6_src, &sa6->sin6_addr, IP6AddrSz); + memcpy(&i6h->ip6_dst, &((struct sockaddr_in6 *)target)->sin6_addr, IP6AddrSz); + } +#endif + + /* Put everything together and send */ + buf_ptr += UDPHdrSz; + memcpy(buf_ptr, msg->payload, msg->len); + + if (send(fd, tee_send_buf, IP4HdrSz+UDPHdrSz+msg->len, 0) == -1) + Log(LOG_ERR, "ERROR ( %s/%s ): raw send() to [%s] failed (%s)\n", config.name, config.type, config.nfprobe_receiver, strerror(errno)); + } + else { + Log(LOG_ERR, "ERROR ( %s/%s ): Can't bridge Address Families when in transparent mode. Exiting ...\n", config.name, config.type); + exit_plugin(1); + } + } +} + +int Tee_prepare_sock(struct sockaddr *addr, socklen_t len) +{ + int s, ret = 0; + + if (!config.tee_transparent) { + struct host_addr source_ip; + struct sockaddr ssource_ip; + + if (config.nfprobe_source_ip) { + ret = str_to_addr(config.nfprobe_source_ip, &source_ip); + addr_to_sa(&ssource_ip, &source_ip, 0); + } + + if ((s = socket(addr->sa_family, SOCK_DGRAM, 0)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + + if (ret && bind(s, (struct sockaddr *) &ssource_ip, sizeof(ssource_ip)) == -1) + Log(LOG_ERR, "ERROR ( %s/%s ): bind() error: %s\n", config.name, config.type, strerror(errno)); + } + else { + if ((s = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW)) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): socket() error: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + } + + /* XXX: SNDBUF tuning? */ + + if (connect(s, (struct sockaddr *)addr, len) == -1) { + Log(LOG_ERR, "ERROR ( %s/%s ): connect() error: %s\n", config.name, config.type, strerror(errno)); + exit_plugin(1); + } + + return(s); +} + +// XXX: duplicate function +void Tee_parse_hostport(const char *s, struct sockaddr *addr, socklen_t *len) +{ + char *orig, *host, *port; + struct addrinfo hints, *res; + int herr; + + if ((host = orig = strdup(s)) == NULL) { + fprintf(stderr, "Out of memory\n"); + exit_plugin(1); + } + + trim_spaces(host); + trim_spaces(orig); + + if ((port = strrchr(host, ':')) == NULL || + *(++port) == '\0' || *host == '\0') { + fprintf(stderr, "Invalid -n argument.\n"); + exit_plugin(1); + } + *(port - 1) = '\0'; + + /* Accept [host]:port for numeric IPv6 addresses */ + if (*host == '[' && *(port - 2) == ']') { + host++; + *(port - 2) = '\0'; + } + + memset(&hints, '\0', sizeof(hints)); + hints.ai_socktype = SOCK_DGRAM; + if ((herr = getaddrinfo(host, port, &hints, &res)) == -1) { + fprintf(stderr, "Address lookup failed: %s\n", + gai_strerror(herr)); + exit_plugin(1); + } + if (res == NULL || res->ai_addr == NULL) { + fprintf(stderr, "No addresses found for [%s]:%s\n", host, port); + exit_plugin(1); + } + if (res->ai_addrlen > *len) { + Log(LOG_ERR, "ERROR ( %s/%s ): Address too long.\n", config.name, config.type); + exit_plugin(1); + } + memcpy(addr, res->ai_addr, res->ai_addrlen); + free(orig); + *len = res->ai_addrlen; +} diff -Nru pmacct-0.12.1/src/tee_plugin/tee_plugin.h pmacct-0.12.5/src/tee_plugin/tee_plugin.h --- pmacct-0.12.1/src/tee_plugin/tee_plugin.h 1970-01-01 00:00:00.000000000 +0000 +++ pmacct-0.12.5/src/tee_plugin/tee_plugin.h 2010-05-13 17:30:42.000000000 +0000 @@ -0,0 +1,44 @@ +/* + pmacct (Promiscuous mode IP Accounting package) + pmacct is Copyright (C) 2003-2010 by Paolo Lucente +*/ + +/* + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if no, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/* includes */ +#include +#include +#include + +/* defines */ +#define DEFAULT_TEE_REFRESH_TIME 10 + +/* prototypes */ +#if (!defined __TEE_PLUGIN_C) +#define EXT extern +#else +#define EXT +#endif + +EXT void Tee_exit_now(int); +EXT void Tee_send(struct pkt_msg *, struct sockaddr *, int); +EXT int Tee_prepare_sock(struct sockaddr *, socklen_t); +EXT void Tee_parse_hostport(const char *, struct sockaddr *, socklen_t *); + +EXT char tee_send_buf[65535]; + +#undef EXT diff -Nru pmacct-0.12.1/src/uacctd.c pmacct-0.12.5/src/uacctd.c --- pmacct-0.12.1/src/uacctd.c 2010-03-17 18:17:37.000000000 +0000 +++ pmacct-0.12.5/src/uacctd.c 2010-10-06 07:26:12.000000000 +0000 @@ -55,7 +55,7 @@ printf("\nGeneral options:\n"); printf(" -h \tShow this page\n"); printf(" -f \tLoad configuration from the specified file\n"); - printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t proto | tos | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | none ] \n\tAggregation string (DEFAULT: src_host)\n"); + printf(" -c \t[ src_mac | dst_mac | vlan | src_host | dst_host | src_net | dst_net | src_port | dst_port |\n\t proto | tos | src_as | dst_as | sum_mac | sum_host | sum_net | sum_as | sum_port | tag |\n\t tag2 | flows | class | tcpflags | in_iface | out_iface | src_mask | dst_mask | cos | none ] \n\tAggregation string (DEFAULT: src_host)\n"); printf(" -D \tDaemonize\n"); printf(" -n \tPath to a file containing Network definitions\n"); printf(" -o \tPath to a file containing Port definitions\n"); @@ -66,14 +66,17 @@ printf(" -R \tRenormalize sampled data\n"); printf(" -g \tNetlink ULOG group\n"); printf(" -L \tNetlink socket read buffer size\n"); - printf("\nMemory Plugin (-P memory) options:\n"); + printf("\nMemory plugin (-P memory) options:\n"); printf(" -p \tSocket for client-server communication (DEFAULT: /tmp/collect.pipe)\n"); printf(" -b \tNumber of buckets\n"); printf(" -m \tNumber of memory pools\n"); printf(" -s \tMemory pool size\n"); printf("\nPostgreSQL (-P pgsql)/MySQL (-P mysql)/SQLite (-P sqlite3) plugin options:\n"); printf(" -r \tRefresh time (in seconds)\n"); - printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 ] \n\tTable version\n"); + printf(" -v \t[ 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 ] \n\tTable version\n"); + printf("\nPrint plugin (-P print) plugin options:\n"); + printf(" -r \tRefresh time (in seconds)\n"); + printf(" -O \t[ formatted | csv ] \n\tOutput format\n"); printf("\n"); printf(" See EXAMPLES or visit http://wiki.pmacct.net/ for examples.\n"); printf("\n"); @@ -194,6 +197,11 @@ strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; + case 'O': + strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN); + strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); + rows++; + break; case 'f': strlcpy(config_file, optarg, sizeof(config_file)); break; @@ -358,7 +366,12 @@ Log(LOG_ERR, "ERROR: Internal packet sampling and external packet sampling are mutual exclusive.\n"); exit(1); } - if (list->type.id == PLUGIN_ID_NFPROBE) { + + if (list->type.id == PLUGIN_ID_TEE) { + Log(LOG_ERR, "ERROR: 'tee' plugin not supported in 'uacctd'.\n"); + exit(1); + } + else if (list->type.id == PLUGIN_ID_NFPROBE) { /* If we already renormalizing an external sampling rate, we cancel the sampling information from the probe plugin */ if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; @@ -388,23 +401,24 @@ if (list->cfg.networks_file || (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP)) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; + list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if (list->cfg.nfprobe_version == 9 && list->cfg.classifiers_path) { list->cfg.what_to_count |= COUNT_CLASS; config.handle_flows = TRUE; } - if (list->cfg.nfprobe_version == 9 && list->cfg.pre_tag_map) { + if (list->cfg.pre_tag_map) { list->cfg.what_to_count |= COUNT_ID; list->cfg.what_to_count |= COUNT_ID2; } list->cfg.what_to_count |= COUNT_IN_IFACE; list->cfg.what_to_count |= COUNT_OUT_IFACE; - if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); - exit(1); + if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| + COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| + COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| + COUNT_IS_SYMMETRIC)) { + Log(LOG_ERR, "ERROR: 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n"); + exit(1); } list->cfg.what_to_count |= COUNT_COUNTERS; @@ -426,6 +440,7 @@ if (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; + list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if (list->cfg.nfacctd_bgp && list->cfg.nfacctd_net == NF_NET_BGP) { list->cfg.what_to_count |= COUNT_SRC_NMASK; @@ -436,13 +451,18 @@ list->cfg.what_to_count |= COUNT_ID2; } if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| - COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_PEER_DST_IP| - COUNT_SRC_STD_COMM|COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED| - COUNT_SRC_LOCAL_PREF|COUNT_IS_SYMMETRIC)) { - Log(LOG_ERR, "ERROR: 'src_as' and 'dst_as' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); + COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| + COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| + COUNT_IS_SYMMETRIC)) { + Log(LOG_ERR, "ERROR: 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n"); exit(1); } +#if defined (HAVE_L2) + list->cfg.what_to_count |= COUNT_VLAN; + list->cfg.what_to_count |= COUNT_COS; +#endif + list->cfg.data_type = PIPE_TYPE_PAYLOAD; } else { diff -Nru pmacct-0.12.1/src/util.c pmacct-0.12.5/src/util.c --- pmacct-0.12.1/src/util.c 2009-12-30 00:42:53.000000000 +0000 +++ pmacct-0.12.5/src/util.c 2010-10-19 11:50:11.000000000 +0000 @@ -169,15 +169,24 @@ void trim_spaces(char *buf) { + char *tmp_buf; int i, len; len = strlen(buf); + + tmp_buf = (char *)malloc(len + 1); + if (tmp_buf == NULL) { + Log(LOG_ERR, "ERROR: trim_spaces: malloc()\n"); + return; + } /* trimming spaces at beginning of the string */ for (i = 0; i <= len; i++) { if (!isspace(buf[i])) { - if (i != 0) - strlcpy(buf, &buf[i], len+1-i); + if (i != 0) { + strlcpy(tmp_buf, &buf[i], len+1-i); + strlcpy(buf, tmp_buf, len+1-i); + } break; } } @@ -188,14 +197,23 @@ buf[i] = '\0'; else break; } + + free(tmp_buf); } void trim_all_spaces(char *buf) { + char *tmp_buf; int i = 0, len, quotes = FALSE; len = strlen(buf); + tmp_buf = (char *)malloc(len + 1); + if (tmp_buf == NULL) { + Log(LOG_ERR, "ERROR: trim_all_spaces: malloc()\n"); + return; + } + /* trimming all spaces */ while (i <= len) { if (buf[i] == '\'') { @@ -203,29 +221,41 @@ else if (quotes) quotes = FALSE; } if (isspace(buf[i]) && !quotes) { - strlcpy(&buf[i], &buf[i+1], len); + strlcpy(tmp_buf, &buf[i+1], len); + strlcpy(&buf[i], tmp_buf, len); len--; } else i++; } + + free(tmp_buf); } void strip_quotes(char *buf) { - char *ptr; + char *ptr, *tmp_buf; int i = 0, len; - ptr = buf; len = strlen(buf); - /* stripping all quote marks */ + tmp_buf = (char *)malloc(len + 1); + if (tmp_buf == NULL) { + Log(LOG_ERR, "ERROR: strip_quotes: malloc()\n"); + return; + } + ptr = buf; + + /* stripping all quote marks using a temporary buffer to avoid string corruption by strcpy() */ while (i <= len) { if (ptr[i] == '\'') { - strcpy(&buf[i], &ptr[i+1]); + strcpy(tmp_buf, &ptr[i+1]); + strcpy(&buf[i], tmp_buf); len--; } else i++; } + + free(tmp_buf); } int isblankline(char *line) @@ -968,6 +998,62 @@ } } +void load_bgp_md5_file(char *filename, struct bgp_md5_table *t) +{ + FILE *file; + char buf[SRVBUFLEN], *ptr; + int index = 0; + + if (filename) { + if ((file = fopen(filename, "r")) == NULL) { + Log(LOG_ERR, "ERROR ( default/core/BGP ): BGP MD5 file '%s' not found\n", filename); + exit(1); + } + + memset(t->table, 0, sizeof(t->table)); + while (!feof(file)) { + if (index >= BGP_MD5_MAP_ENTRIES) break; /* XXX: we shouldn't exit silently */ + memset(buf, 0, SRVBUFLEN); + if (fgets(buf, SRVBUFLEN, file)) { + if (!sanitize_buf(buf)) { + char *endptr, *token; + int tk_idx = 0, ret = 0, len = 0; + + ptr = buf; + memset(&t->table[index], 0, sizeof(t->table[index])); + while ( (token = extract_token(&ptr, ',')) && tk_idx < 2 ) { + if (tk_idx == 0) ret = str_to_addr(token, &t->table[index].addr); + else if (tk_idx == 1) { + strlcpy(t->table[index].key, token, TCP_MD5SIG_MAXKEYLEN); + len = strlen(t->table[index].key); + } + tk_idx++; + } + + if (ret > 0 && len > 0) index++; + else Log(LOG_WARNING, "WARN ( default/core/BGP ): 'bgp_daemon_md5_file': line '%s' ignored.\n", buf); + } + } + } + t->num = index; + + /* Set to -1 to distinguish between no map and empty map conditions */ + if (!t->num) t->num = -1; + + fclose(file); + } +} + +void unload_bgp_md5_file(struct bgp_md5_table *t) +{ + int index = 0; + + while (index < t->num) { + memset(t->table[index].key, 0, TCP_MD5SIG_MAXKEYLEN); + index++; + } +} + int check_allow(struct hosts_table *allow, struct sockaddr *sa) { int index; diff -Nru pmacct-0.12.1/src/util.h pmacct-0.12.5/src/util.h --- pmacct-0.12.1/src/util.h 2009-12-29 00:15:37.000000000 +0000 +++ pmacct-0.12.5/src/util.h 2010-06-25 16:48:06.000000000 +0000 @@ -74,6 +74,8 @@ EXT void *Malloc(unsigned int); EXT void load_allow_file(char *, struct hosts_table *); EXT int check_allow(struct hosts_table *, struct sockaddr *); +EXT void load_bgp_md5_file(char *, struct bgp_md5_table *); +EXT void unload_bgp_md5_file(struct bgp_md5_table *); EXT unsigned int str_to_addr(const char *, struct host_addr *); diff -Nru pmacct-0.12.1/src/xflow_status.c pmacct-0.12.5/src/xflow_status.c --- pmacct-0.12.1/src/xflow_status.c 2009-10-03 21:14:37.000000000 +0000 +++ pmacct-0.12.5/src/xflow_status.c 2010-12-21 16:56:51.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2009 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -46,11 +46,12 @@ struct xflow_status_entry *search_status_table(struct sockaddr *sa, u_int32_t aux1, int hash, int num_entries) { - struct xflow_status_entry *entry = xflow_status_table[hash]; + struct xflow_status_entry *entry = xflow_status_table[hash], *saved = NULL; u_int16_t port; cycle_again: if (entry) { + saved = entry; if (!sa_addr_cmp(sa, &entry->agent_addr) && aux1 == entry->aux1); /* FOUND IT: we are finished */ else { entry = entry->next; @@ -67,7 +68,8 @@ entry->aux1 = aux1; entry->seqno = 0; entry->next = FALSE; - if (!xflow_status_table[hash]) xflow_status_table[hash] = entry; + if (!saved) xflow_status_table[hash] = entry; + else saved->next = entry; xflow_status_table_error = TRUE; xflow_status_table_entries++; } @@ -225,6 +227,58 @@ return new; } +struct xflow_status_entry_class * +search_class_id_status_table(struct xflow_status_entry_class *centry, pm_class_t class_id) +{ + while (centry) { + if (centry->class_id == class_id) return centry; + centry = centry->next; + } + + return NULL; +} + +struct xflow_status_entry_class * +create_class_entry_status_table(struct xflow_status_entry *entry) +{ + struct xflow_status_entry_class *centry = entry->class, *new = NULL; + + if (centry) { + while (centry->next) centry = centry->next; + } + + if (xflow_status_table_entries < XFLOW_STATUS_TABLE_MAX_ENTRIES) { + new = malloc(sizeof(struct xflow_status_entry_class)); + if (!new) { + if (class_entry_status_table_memerr) { + Log(LOG_ERR, "ERROR: unable to allocate more entries into the xflow classification table.\n"); + class_entry_status_table_memerr = FALSE; + } + } + else { + if (!entry->class) entry->class = new; + if (centry) centry->next = new; + new->next = FALSE; + class_entry_status_table_memerr = TRUE; + xflow_status_table_entries++; + } + } + + return new; +} + +pm_class_t NF_evaluate_classifiers(struct xflow_status_entry_class *entry, pm_class_t *class_id) +{ + struct xflow_status_entry_class *centry; + + centry = search_class_id_status_table(entry, *class_id); + if (centry) { + return centry->class_int_id; + } + + return 0; +} + void set_vector_f_status(struct packet_ptrs_vector *pptrsv) { pptrsv->vlan4.f_status = pptrsv->v4.f_status; diff -Nru pmacct-0.12.1/src/xflow_status.h pmacct-0.12.5/src/xflow_status.h --- pmacct-0.12.1/src/xflow_status.h 2009-10-03 21:14:37.000000000 +0000 +++ pmacct-0.12.5/src/xflow_status.h 2010-12-21 16:56:51.000000000 +0000 @@ -1,6 +1,6 @@ /* pmacct (Promiscuous mode IP Accounting package) - pmacct is Copyright (C) 2003-2008 by Paolo Lucente + pmacct is Copyright (C) 2003-2010 by Paolo Lucente */ /* @@ -41,6 +41,14 @@ struct xflow_status_entry_sampling *next; }; +struct xflow_status_entry_class +{ + pm_class_t class_id; /* NetFlow v9: classfier ID field */ + pm_class_t class_int_id; /* NetFlow v9: internal classfier ID field */ + char class_name[MAX_PROTOCOL_LEN]; /* NetFlow v9: classfier name field */ + struct xflow_status_entry_class *next; +}; + struct xflow_status_entry { struct host_addr agent_addr; /* xFlow agent IP address */ @@ -50,8 +58,10 @@ NetFlow v9: Source ID sFlow v5: agentSubID */ u_int16_t inc; /* increment, NetFlow v5: required by flow sequence number */ + u_int32_t peer_idx; /* last known BGP peer index */ struct xflow_status_entry_counters counters; struct xflow_status_entry_sampling *sampling; + struct xflow_status_entry_class *class; struct xflow_status_entry *next; }; @@ -69,11 +79,14 @@ EXT struct xflow_status_entry_sampling *search_smp_if_status_table(struct xflow_status_entry_sampling *, u_int32_t); EXT struct xflow_status_entry_sampling *search_smp_id_status_table(struct xflow_status_entry_sampling *, u_int8_t); EXT struct xflow_status_entry_sampling *create_smp_entry_status_table(struct xflow_status_entry *); +EXT struct xflow_status_entry_class *search_class_id_status_table(struct xflow_status_entry_class *, pm_class_t); +EXT struct xflow_status_entry_class *create_class_entry_status_table(struct xflow_status_entry *); +EXT pm_class_t NF_evaluate_classifier(struct xflow_status_entry_class *, pm_class_t *); EXT struct xflow_status_entry *xflow_status_table[XFLOW_STATUS_TABLE_SZ]; EXT u_int32_t xflow_status_table_entries; EXT u_int8_t xflow_status_table_error; EXT u_int32_t xflow_tot_bad_datagrams; -EXT u_int8_t smp_entry_status_table_memerr; +EXT u_int8_t smp_entry_status_table_memerr, class_entry_status_table_memerr; EXT void set_vector_f_status(struct packet_ptrs_vector *); #undef EXT diff -Nru pmacct-0.12.1/TOOLS pmacct-0.12.5/TOOLS --- pmacct-0.12.1/TOOLS 2009-10-18 13:50:18.000000000 +0000 +++ pmacct-0.12.5/TOOLS 2010-05-14 15:06:58.000000000 +0000 @@ -1,28 +1,29 @@ -pmacct (Promiscuous mode IP Accounting package) -pmacct is Copyright (C) 2003-2008 by Paolo Lucente +TOOLS DESCRIPTION. -pmacctd pcap-based accounting daemon; it gathers packets from an - interface it is bound to (enabling optionally Promiscuous - mode); statistics may be either pushed to stdout, stored - in a memory table or a PostgreSQL/MySQL/SQLite database. +pmacctd libpcap-based accounting daemon; it captures packets from an + interface it is bound to. Statistics can be printed to stdout, + stored in memory tables or a PostgreSQL/MySQL/SQLite database, + exported via NetFlow or sFlow protocols. nfacctd NetFlow accounting daemon; it listens for NetFlow packets v1/v5/v7/v8/v9 on one or more interfaces (IPv4 and IPv6); - statistics may be either pushed to stdout, stored in a - memory table or a PostgreSQL/MySQL/SQLite database. + statistics can be printed to stdout, stored in memory tables + or a PostgreSQL/MySQL/SQLite database, replicated to other + collectors. sfacctd sFlow accounting daemon; it listens for sFlow packets v2, v4 and v5 on one or more interfaces (both IPv4 and IPv6); - statistics may be either pushed to stdout, stored in a - memory table or a PostgreSQL/MySQL/SQLite database. -uacctd Linux Netlink ULOG accounting daemon; it gathers packets - from a ULOG multicast group and works only on Linux; - statistics may be either pushed to stdout, stored in a - memory table or a PostgreSQL/MySQL/SQLite database. -pmacct commandline pmacct client; used to retrieve data from an - active memroy plugin; it may ask for specific entries, - partial fields or perform a bulk data retrieval; output - may be text-formatted or 'counters-only', highly suitable - for data injection in tools like MRTG, RRDtool, Gnuplot - or SNMP server among the others. + statistics can be printed to stdout, stored in memory tables + or a PostgreSQL/MySQL/SQLite database, replicated to other + collectors. +uacctd Linux Netlink ULOG accounting daemon; it captures packets by + leveraging a ULOG multicast group - and works only on Linux; + Statistics can be printed to stdout, stored in memory tables + or a PostgreSQL/MySQL/SQLite database, exported via NetFlow + or sFlow protocols. +pmacct commandline pmacct client; used to retrieve data from a + memory plugin; it can execute both partial and full data + retrieval. Output is either formatted or 'counters-only', + suitable for data injection in tools like MRTG, RRDtool, + Gnuplot or SNMP server among the others. pmmyplay pmacct MySQL logfile player; it plays logfiles previously generated by a MySQL plugin. pmpgplay pmacct PgSQL logfile player; it plays logfiles previously