Browse Source

[master] Merge branch 'trac2884'

Naoki Kambe 11 years ago
parent
commit
c0153581c3

+ 92 - 83
src/bin/xfrin/b10-xfrin.xml

@@ -231,98 +231,107 @@ operation
           <variablelist>
           <variablelist>
 
 
             <varlistentry>
             <varlistentry>
-              <term><replaceable>zonename</replaceable></term>
+              <term><replaceable>classname</replaceable></term>
               <listitem><simpara>
               <listitem><simpara>
-                An actual zone name or special zone name
-                <quote>_SERVER_</quote> representing the entire server.
-                Zone classes (e.g. IN, CH, and HS) are mixed and counted so
-                far. But these will be distinguished in future release.
+                An actual RR class name of the zone, e.g. IN, CH, and HS
                 </simpara>
                 </simpara>
                 <variablelist>
                 <variablelist>
 
 
                   <varlistentry>
                   <varlistentry>
-                    <term>soaoutv4</term>
+                    <term><replaceable>zonename</replaceable></term>
                     <listitem><simpara>
                     <listitem><simpara>
-                      Number of IPv4 SOA queries sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>soaoutv6</term>
-                    <listitem><simpara>
-                      Number of IPv6 SOA queries sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>axfrreqv4</term>
-                    <listitem><simpara>
-                      Number of IPv4 AXFR requests sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>axfrreqv6</term>
-                    <listitem><simpara>
-                      Number of IPv6 AXFR requests sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>ixfrreqv4</term>
-                    <listitem><simpara>
-                      Number of IPv4 IXFR requests sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>ixfrreqv6</term>
-                    <listitem><simpara>
-                      Number of IPv6 IXFR requests sent from Xfrin
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>xfrsuccess</term>
-                    <listitem><simpara>
-                      Number of zone transfer requests succeeded.
-                      These include the case where the zone turns
-                      out to be the latest as a result of an
-                      initial SOA query (and there is actually no
-                      AXFR or IXFR transaction).
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>xfrfail</term>
-                    <listitem><simpara>
-                      Number of zone transfer requests failed
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>last_axfr_duration</term>
-                    <listitem><simpara>
-                      Duration in seconds of the last successful AXFR.  0.0
-                      means no successful AXFR done or means a successful AXFR
-                      done in less than a microsecond.  If an AXFR is aborted
-                      due to some failure, this duration won't be updated.
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>last_ixfr_duration</term>
-                    <listitem><simpara>
-                      Duration in seconds of the last successful IXFR.  0.0
-                      means no successful IXFR done or means a successful IXFR
-                      done in less than a microsecond.  If an IXFR is aborted
-                      due to some failure, this duration won't be updated.
-                    </simpara></listitem>
-                  </varlistentry>
+                      An actual zone name or special zone name
+                      <quote>_SERVER_</quote> representing the entire server
+                      </simpara>
+                      <variablelist>
+
+                        <varlistentry>
+                          <term>soaoutv4</term>
+                          <listitem><simpara>
+                            Number of IPv4 SOA queries sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>soaoutv6</term>
+                          <listitem><simpara>
+                            Number of IPv6 SOA queries sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>axfrreqv4</term>
+                          <listitem><simpara>
+                            Number of IPv4 AXFR requests sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>axfrreqv6</term>
+                          <listitem><simpara>
+                            Number of IPv6 AXFR requests sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>ixfrreqv4</term>
+                          <listitem><simpara>
+                            Number of IPv4 IXFR requests sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>ixfrreqv6</term>
+                          <listitem><simpara>
+                            Number of IPv6 IXFR requests sent from Xfrin
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>xfrsuccess</term>
+                          <listitem><simpara>
+                            Number of zone transfer requests succeeded.
+                            These include the case where the zone turns
+                            out to be the latest as a result of an
+                            initial SOA query (and there is actually no
+                            AXFR or IXFR transaction).
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>xfrfail</term>
+                          <listitem><simpara>
+                            Number of zone transfer requests failed
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>last_axfr_duration</term>
+                          <listitem><simpara>
+                            Duration in seconds of the last successful AXFR.  0.0
+                            means no successful AXFR done or means a successful AXFR
+                            done in less than a microsecond.  If an AXFR is aborted
+                            due to some failure, this duration won't be updated.
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>last_ixfr_duration</term>
+                          <listitem><simpara>
+                            Duration in seconds of the last successful IXFR.  0.0
+                            means no successful IXFR done or means a successful IXFR
+                            done in less than a microsecond.  If an IXFR is aborted
+                            due to some failure, this duration won't be updated.
+                          </simpara></listitem>
+                        </varlistentry>
+
+                      </variablelist>
+                    </listitem>
+                  </varlistentry><!-- end of zonename -->
 
 
                 </variablelist>
                 </variablelist>
               </listitem>
               </listitem>
-            </varlistentry><!-- end of zonename -->
+            </varlistentry><!-- end of classname -->
 
 
           </variablelist>
           </variablelist>
         </listitem>
         </listitem>

+ 1 - 0
src/bin/xfrin/tests/xfrin_test.py

@@ -2182,6 +2182,7 @@ class TestStatisticsXfrinConn(TestXfrinConnection):
         name2count.update(overwrite)
         name2count.update(overwrite)
         for (name, exp) in name2count.items():
         for (name, exp) in name2count.items():
             act = self.conn._counters.get(self.__zones,
             act = self.conn._counters.get(self.__zones,
+                                          TEST_RRCLASS_STR,
                                           TEST_ZONE_NAME_STR,
                                           TEST_ZONE_NAME_STR,
                                           name)
                                           name)
             msg = '%s is expected %s but actually %s' % (name, exp, act)
             msg = '%s is expected %s but actually %s' % (name, exp, act)

+ 15 - 7
src/bin/xfrin/xfrin.py.in

@@ -875,8 +875,9 @@ class XfrinConnection(asyncore.dispatcher):
 
 
         self._send_query(RRType.SOA)
         self._send_query(RRType.SOA)
         # count soaoutv4 or soaoutv6 requests
         # count soaoutv4 or soaoutv6 requests
-        self._counters.inc('zones', self._zone_name.to_text(),
-                           'soaout' + self._get_ipver_str())
+        self._counters.inc('zones', self._rrclass.to_text(),
+                           self._zone_name.to_text(), 'soaout' +
+                           self._get_ipver_str())
         data_len = self._get_request_response(2)
         data_len = self._get_request_response(2)
         msg_len = socket.htons(struct.unpack('H', data_len)[0])
         msg_len = socket.htons(struct.unpack('H', data_len)[0])
         soa_response = self._get_request_response(msg_len)
         soa_response = self._get_request_response(msg_len)
@@ -918,12 +919,17 @@ class XfrinConnection(asyncore.dispatcher):
             # Note: If the timer for the zone is already started but
             # Note: If the timer for the zone is already started but
             # not yet stopped due to some error, the last start time
             # not yet stopped due to some error, the last start time
             # is overwritten at this point.
             # is overwritten at this point.
-            self._counters.start_timer('zones', self._zone_name.to_text(),
-                                       'last_' + req_str.lower() + '_duration')
+            self._counters.start_timer('zones',
+                                       self._rrclass.to_text(),
+                                       self._zone_name.to_text(),
+                                       'last_' + req_str.lower() +
+                                       '_duration')
             logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
             logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
             # An AXFR or IXFR is being requested.
             # An AXFR or IXFR is being requested.
-            self._counters.inc('zones', self._zone_name.to_text(),
-                               req_str.lower() + 'req' + self._get_ipver_str())
+            self._counters.inc('zones', self._rrclass.to_text(),
+                               self._zone_name.to_text(),
+                               req_str.lower() + 'req' +
+                               self._get_ipver_str())
             self._send_query(self._request_type)
             self._send_query(self._request_type)
             self.__state = XfrinInitialSOA()
             self.__state = XfrinInitialSOA()
             self._handle_xfrin_responses()
             self._handle_xfrin_responses()
@@ -988,11 +994,13 @@ class XfrinConnection(asyncore.dispatcher):
             # A xfrsuccess or xfrfail counter is incremented depending on
             # A xfrsuccess or xfrfail counter is incremented depending on
             # the result.
             # the result.
             result = {XFRIN_OK: 'xfrsuccess', XFRIN_FAIL: 'xfrfail'}[ret]
             result = {XFRIN_OK: 'xfrsuccess', XFRIN_FAIL: 'xfrfail'}[ret]
-            self._counters.inc('zones', self._zone_name.to_text(), result)
+            self._counters.inc('zones', self._rrclass.to_text(),
+                               self._zone_name.to_text(), result)
             # The started statistics timer is finally stopped only in
             # The started statistics timer is finally stopped only in
             # a successful case.
             # a successful case.
             if ret == XFRIN_OK:
             if ret == XFRIN_OK:
                 self._counters.stop_timer('zones',
                 self._counters.stop_timer('zones',
+                                          self._rrclass.to_text(),
                                           self._zone_name.to_text(),
                                           self._zone_name.to_text(),
                                           'last_' + req_str.lower() +
                                           'last_' + req_str.lower() +
                                           '_duration')
                                           '_duration')

+ 107 - 97
src/bin/xfrin/xfrin.spec

@@ -135,110 +135,120 @@
         "item_type": "named_set",
         "item_type": "named_set",
         "item_optional": false,
         "item_optional": false,
         "item_default": {
         "item_default": {
-          "_SERVER_" : {
-            "soaoutv4": 0,
-            "soaoutv6": 0,
-            "axfrreqv4": 0,
-            "axfrreqv6": 0,
-            "ixfrreqv4": 0,
-            "ixfrreqv6": 0,
-            "xfrsuccess": 0,
-            "xfrfail": 0,
-            "last_ixfr_duration": 0.0,
-            "last_axfr_duration": 0.0
+          "IN" : {
+            "_SERVER_" : {
+              "soaoutv4": 0,
+              "soaoutv6": 0,
+              "axfrreqv4": 0,
+              "axfrreqv6": 0,
+              "ixfrreqv4": 0,
+              "ixfrreqv6": 0,
+              "xfrsuccess": 0,
+              "xfrfail": 0,
+              "last_ixfr_duration": 0.0,
+              "last_axfr_duration": 0.0
+            }
           }
           }
         },
         },
         "item_title": "Zone names",
         "item_title": "Zone names",
         "item_description": "A directory name of per-zone statistics",
         "item_description": "A directory name of per-zone statistics",
         "named_set_item_spec": {
         "named_set_item_spec": {
-          "item_name": "zonename",
-          "item_type": "map",
+          "item_name": "classname",
+          "item_type": "named_set",
           "item_optional": false,
           "item_optional": false,
           "item_default": {},
           "item_default": {},
-          "item_title": "Zone name",
-          "item_description": "An actual zone name or special zone name _SERVER_ representing the entire server. Zone classes (e.g. IN, CH, and HS) are mixed and counted so far. But these will be distinguished in future release.",
-          "map_item_spec": [
-            {
-              "item_name": "soaoutv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "SOAOutv4",
-              "item_description": "Number of IPv4 SOA queries sent from Xfrin"
-            },
-            {
-              "item_name": "soaoutv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "SOAOutv6",
-              "item_description": "Number of IPv6 SOA queries sent from Xfrin"
-            },
-            {
-              "item_name": "axfrreqv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "AXFRReqv4",
-              "item_description": "Number of IPv4 AXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "axfrreqv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "AXFRReqv6",
-              "item_description": "Number of IPv6 AXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "ixfrreqv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IXFRReqv4",
-              "item_description": "Number of IPv4 IXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "ixfrreqv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IXFRReqv6",
-              "item_description": "Number of IPv6 IXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "xfrsuccess",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "XfrSuccess",
-              "item_description": "Number of zone transfer requests succeeded. These include the case where the zone turns out to be the latest as a result of an initial SOA query (and there is actually no AXFR or IXFR transaction)."
-            },
-            {
-              "item_name": "xfrfail",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "XfrFail",
-              "item_description": "Number of zone transfer requests failed"
-            },
-            {
-              "item_name": "last_axfr_duration",
-              "item_type": "real",
-              "item_optional": false,
-              "item_default": 0.0,
-              "item_title": "Last AXFR duration",
-              "item_description": "Duration in seconds of the last successful AXFR.  0.0 means no successful AXFR done or means a successful AXFR done in less than a microsecond.  If an AXFR is aborted due to some failure, this duration won't be updated."
-            },
-            {
-              "item_name": "last_ixfr_duration",
-              "item_type": "real",
-              "item_optional": false,
-              "item_default": 0.0,
-              "item_title": "Last IXFR duration",
-              "item_description": "Duration in seconds of the last successful IXFR.  0.0 means no successful IXFR done or means a successful IXFR done in less than a microsecond.  If an IXFR is aborted due to some failure, this duration won't be updated."
-            }
-          ]
+          "item_title": "RR class name",
+          "item_description": "An actual RR class name of the zone, e.g. IN, CH, and HS",
+          "named_set_item_spec": {
+            "item_name": "zonename",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {},
+            "item_title": "Zone name",
+            "item_description": "An actual zone name or special zone name _SERVER_ representing the entire server",
+            "map_item_spec": [
+              {
+                "item_name": "soaoutv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "SOAOutv4",
+                "item_description": "Number of IPv4 SOA queries sent from Xfrin"
+              },
+              {
+                "item_name": "soaoutv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "SOAOutv6",
+                "item_description": "Number of IPv6 SOA queries sent from Xfrin"
+              },
+              {
+                "item_name": "axfrreqv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "AXFRReqv4",
+                "item_description": "Number of IPv4 AXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "axfrreqv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "AXFRReqv6",
+                "item_description": "Number of IPv6 AXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "ixfrreqv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IXFRReqv4",
+                "item_description": "Number of IPv4 IXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "ixfrreqv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IXFRReqv6",
+                "item_description": "Number of IPv6 IXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "xfrsuccess",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "XfrSuccess",
+                "item_description": "Number of zone transfer requests succeeded. These include the case where the zone turns out to be the latest as a result of an initial SOA query (and there is actually no AXFR or IXFR transaction)."
+              },
+              {
+                "item_name": "xfrfail",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "XfrFail",
+                "item_description": "Number of zone transfer requests failed"
+              },
+              {
+                "item_name": "last_axfr_duration",
+                "item_type": "real",
+                "item_optional": false,
+                "item_default": 0.0,
+                "item_title": "Last AXFR duration",
+                "item_description": "Duration in seconds of the last successful AXFR.  0.0 means no successful AXFR done or means a successful AXFR done in less than a microsecond.  If an AXFR is aborted due to some failure, this duration won't be updated."
+              },
+              {
+                "item_name": "last_ixfr_duration",
+                "item_type": "real",
+                "item_optional": false,
+                "item_default": 0.0,
+                "item_title": "Last IXFR duration",
+                "item_description": "Duration in seconds of the last successful IXFR.  0.0 means no successful IXFR done or means a successful IXFR done in less than a microsecond.  If an IXFR is aborted due to some failure, this duration won't be updated."
+              }
+            ]
+          }
         }
         }
       }
       }
     ]
     ]

+ 41 - 29
src/bin/xfrout/b10-xfrout.xml

@@ -171,44 +171,56 @@
           <variablelist>
           <variablelist>
 
 
             <varlistentry>
             <varlistentry>
-              <term><replaceable>zonename</replaceable></term>
+              <term><replaceable>classname</replaceable></term>
               <listitem><simpara>
               <listitem><simpara>
-                A actual zone name or special zone name <quote>_SERVER_</quote>
-                representing an entire server
+                An actual RR class name of the zone, e.g. IN, CH, and HS
                 </simpara>
                 </simpara>
                 <variablelist>
                 <variablelist>
 
 
                   <varlistentry>
                   <varlistentry>
-                    <term>notifyoutv4</term>
+                    <term><replaceable>zonename</replaceable></term>
                     <listitem><simpara>
                     <listitem><simpara>
-                      Number of IPv4 notifies per zone name sent out from Xfrout
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>notifyoutv6</term>
-                    <listitem><simpara>
-                      Number of IPv6 notifies per zone name sent out from Xfrout
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>xfrrej</term>
-                    <listitem><simpara>
-                      Number of XFR requests per zone name rejected by Xfrout
-                    </simpara></listitem>
-                  </varlistentry>
-
-                  <varlistentry>
-                    <term>xfrreqdone</term>
-                    <listitem><simpara>
-                      Number of requested zone transfers per zone name completed
-                    </simpara></listitem>
-                  </varlistentry>
+                      An actual zone name or special zone
+                      name <quote>_SERVER_</quote> representing an entire
+                      server
+                      </simpara>
+                      <variablelist>
+
+                        <varlistentry>
+                          <term>notifyoutv4</term>
+                          <listitem><simpara>
+                            Number of IPv4 notifies per zone name sent out from Xfrout
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>notifyoutv6</term>
+                          <listitem><simpara>
+                            Number of IPv6 notifies per zone name sent out from Xfrout
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>xfrrej</term>
+                          <listitem><simpara>
+                            Number of XFR requests per zone name rejected by Xfrout
+                          </simpara></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
+                          <term>xfrreqdone</term>
+                          <listitem><simpara>
+                            Number of requested zone transfers per zone name completed
+                          </simpara></listitem>
+                        </varlistentry>
+
+                      </variablelist>
+                    </listitem>
+                  </varlistentry><!-- end of zonename -->
 
 
                 </variablelist>
                 </variablelist>
               </listitem>
               </listitem>
-            </varlistentry><!-- end of zonename -->
+            </varlistentry><!-- end of classname -->
 
 
           </variablelist>
           </variablelist>
         </listitem>
         </listitem>

+ 20 - 10
src/bin/xfrout/tests/xfrout_test.py.in

@@ -1,4 +1,4 @@
-# Copyright (C) 2010-2012  Internet Systems Consortium.
+# Copyright (C) 2010-2013  Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -41,6 +41,7 @@ TSIG_KEY = TSIGKey("example.com:SFuWd/q99SzF8Yzd1QbB9g==")
 TEST_ZONE_NAME_STR = "example.com."
 TEST_ZONE_NAME_STR = "example.com."
 TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
 TEST_ZONE_NAME = Name(TEST_ZONE_NAME_STR)
 TEST_RRCLASS = RRClass.IN
 TEST_RRCLASS = RRClass.IN
+TEST_RRCLASS_STR = TEST_RRCLASS.to_text()
 IXFR_OK_VERSION = 2011111802
 IXFR_OK_VERSION = 2011111802
 IXFR_NG_VERSION = 2011111803
 IXFR_NG_VERSION = 2011111803
 SOA_CURRENT_VERSION = 2011112001
 SOA_CURRENT_VERSION = 2011112001
@@ -441,7 +442,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         # check the 'xfrrej' counter initially
         # check the 'xfrrej' counter initially
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self.xfrsess._counters.get, 'zones',
                           self.xfrsess._counters.get, 'zones',
-                          TEST_ZONE_NAME_STR, 'xfrrej')
+                          TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                          'xfrrej')
         # Localhost (the default in this test) is accepted
         # Localhost (the default in this test) is accepted
         rcode, msg = self.xfrsess._parse_query_message(self.mdata)
         rcode, msg = self.xfrsess._parse_query_message(self.mdata)
         self.assertEqual(rcode.to_text(), "NOERROR")
         self.assertEqual(rcode.to_text(), "NOERROR")
@@ -457,7 +459,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 1)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 1)
 
 
         # TSIG signed request
         # TSIG signed request
         request_data = self.create_request_data(with_tsig=True)
         request_data = self.create_request_data(with_tsig=True)
@@ -488,7 +491,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 2)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 2)
 
 
         # ACL using TSIG: no TSIG; should be rejected
         # ACL using TSIG: no TSIG; should be rejected
         acl_setter(isc.acl.dns.REQUEST_LOADER.load([
         acl_setter(isc.acl.dns.REQUEST_LOADER.load([
@@ -498,7 +502,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 3)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 3)
 
 
         #
         #
         # ACL using IP + TSIG: both should match
         # ACL using IP + TSIG: both should match
@@ -520,7 +525,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 4)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 4)
         # Address matches, but TSIG doesn't (not included)
         # Address matches, but TSIG doesn't (not included)
         self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
         self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
                                 ('192.0.2.1', 12345))
                                 ('192.0.2.1', 12345))
@@ -528,7 +534,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 5)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 5)
         # Neither address nor TSIG matches
         # Neither address nor TSIG matches
         self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
         self.xfrsess._remote = (socket.AF_INET, socket.SOCK_STREAM,
                                 ('192.0.2.2', 12345))
                                 ('192.0.2.2', 12345))
@@ -536,7 +543,8 @@ class TestXfroutSession(TestXfroutSessionBase):
         self.assertEqual(rcode.to_text(), "REFUSED")
         self.assertEqual(rcode.to_text(), "REFUSED")
         # check the 'xfrrej' counter after incrementing
         # check the 'xfrrej' counter after incrementing
         self.assertEqual(self.xfrsess._counters.get(
         self.assertEqual(self.xfrsess._counters.get(
-                'zones', TEST_ZONE_NAME_STR, 'xfrrej'), 6)
+                'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+                'xfrrej'), 6)
 
 
     def test_transfer_acl(self):
     def test_transfer_acl(self):
         # ACL checks only with the default ACL
         # ACL checks only with the default ACL
@@ -936,12 +944,14 @@ class TestXfroutSession(TestXfroutSessionBase):
 
 
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self.xfrsess._counters.get,
                           self.xfrsess._counters.get,
-                          'zones', TEST_ZONE_NAME_STR, 'xfrreqdone')
+                          'zones', TEST_RRCLASS_STR,
+                          TEST_ZONE_NAME_STR, 'xfrreqdone')
         self.xfrsess._reply_xfrout_query = myreply
         self.xfrsess._reply_xfrout_query = myreply
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         self.xfrsess.dns_xfrout_start(self.sock, self.mdata)
         self.assertEqual(self.sock.readsent(), b"success")
         self.assertEqual(self.sock.readsent(), b"success")
         self.assertGreater(self.xfrsess._counters.get(
         self.assertGreater(self.xfrsess._counters.get(
-            'zones', TEST_ZONE_NAME_STR, 'xfrreqdone'), 0)
+            'zones', TEST_RRCLASS_STR, TEST_ZONE_NAME_STR,
+            'xfrreqdone'), 0)
 
 
     def test_reply_xfrout_query_axfr(self):
     def test_reply_xfrout_query_axfr(self):
         self.xfrsess._soa = self.soa_rrset
         self.xfrsess._soa = self.soa_rrset

+ 4 - 2
src/bin/xfrout/xfrout.py.in

@@ -301,7 +301,8 @@ class XfroutSession():
             return None, None
             return None, None
         elif acl_result == REJECT:
         elif acl_result == REJECT:
             # count rejected Xfr request by each zone name
             # count rejected Xfr request by each zone name
-            self._counters.inc('zones', zone_name.to_text(), 'xfrrej')
+            self._counters.inc('zones', zone_class.to_text(),
+                               zone_name.to_text(), 'xfrrej')
             logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
             logger.debug(DBG_XFROUT_TRACE, XFROUT_QUERY_REJECTED,
                          self._request_type, format_addrinfo(self._remote),
                          self._request_type, format_addrinfo(self._remote),
                          format_zone_str(zone_name, zone_class))
                          format_zone_str(zone_name, zone_class))
@@ -571,7 +572,8 @@ class XfroutSession():
             else:
             else:
                 self._counters.dec('ixfr_running')
                 self._counters.dec('ixfr_running')
         # count done Xfr requests by each zone name
         # count done Xfr requests by each zone name
-        self._counters.inc('zones', zone_name.to_text(), 'xfrreqdone')
+        self._counters.inc('zones', zone_class.to_text(),
+                           zone_name.to_text(), 'xfrreqdone')
         logger.info(XFROUT_XFR_TRANSFER_DONE, self._request_typestr,
         logger.info(XFROUT_XFR_TRANSFER_DONE, self._request_typestr,
                     format_addrinfo(self._remote), zone_str)
                     format_addrinfo(self._remote), zone_str)
 
 

+ 53 - 43
src/bin/xfrout/xfrout.spec.pre.in

@@ -121,56 +121,66 @@
           "item_type": "named_set",
           "item_type": "named_set",
           "item_optional": false,
           "item_optional": false,
           "item_default": {
           "item_default": {
-            "_SERVER_" : {
-              "notifyoutv4" : 0,
-              "notifyoutv6" : 0,
-              "xfrrej" : 0,
-              "xfrreqdone" : 0
+            "IN" : {
+              "_SERVER_" : {
+                "notifyoutv4" : 0,
+                "notifyoutv6" : 0,
+                "xfrrej" : 0,
+                "xfrreqdone" : 0
+              }
             }
             }
           },
           },
           "item_title": "Zone names",
           "item_title": "Zone names",
           "item_description": "A directory name of per-zone statistics",
           "item_description": "A directory name of per-zone statistics",
           "named_set_item_spec": {
           "named_set_item_spec": {
-            "item_name": "zonename",
-            "item_type": "map",
+            "item_name": "classname",
+            "item_type": "named_set",
             "item_optional": false,
             "item_optional": false,
             "item_default": {},
             "item_default": {},
-            "item_title": "Zone name",
-            "item_description": "A actual zone name or special zone name _SERVER_ representing an entire server",
-            "map_item_spec": [
-              {
-                "item_name": "notifyoutv4",
-                "item_type": "integer",
-                "item_optional": false,
-                "item_default": 0,
-                "item_title": "IPv4 notifies",
-                "item_description": "Number of IPv4 notifies per zone name sent out from Xfrout"
-              },
-              {
-                "item_name": "notifyoutv6",
-                "item_type": "integer",
-                "item_optional": false,
-                "item_default": 0,
-                "item_title": "IPv6 notifies",
-                "item_description": "Number of IPv6 notifies per zone name sent out from Xfrout"
-              },
-              {
-                "item_name": "xfrrej",
-                "item_type": "integer",
-                "item_optional": false,
-                "item_default": 0,
-                "item_title": "XFR rejected requests",
-                "item_description": "Number of XFR requests per zone name rejected by Xfrout"
-              },
-              {
-                "item_name": "xfrreqdone",
-                "item_type": "integer",
-                "item_optional": false,
-                "item_default": 0,
-                "item_title": "Requested zone transfers",
-                "item_description": "Number of requested zone transfers completed per zone name"
-              }
-            ]
+            "item_title": "RR class name",
+            "item_description": "An actual RR class name of the zone, e.g. IN, CH, and HS",
+            "named_set_item_spec": {
+              "item_name": "zonename",
+              "item_type": "map",
+              "item_optional": false,
+              "item_default": {},
+              "item_title": "Zone name",
+              "item_description": "An actual zone name or special zone name _SERVER_ representing an entire server",
+              "map_item_spec": [
+                {
+                  "item_name": "notifyoutv4",
+                  "item_type": "integer",
+                  "item_optional": false,
+                  "item_default": 0,
+                  "item_title": "IPv4 notifies",
+                  "item_description": "Number of IPv4 notifies per zone name sent out from Xfrout"
+                },
+                {
+                  "item_name": "notifyoutv6",
+                  "item_type": "integer",
+                  "item_optional": false,
+                  "item_default": 0,
+                  "item_title": "IPv6 notifies",
+                  "item_description": "Number of IPv6 notifies per zone name sent out from Xfrout"
+                },
+                {
+                  "item_name": "xfrrej",
+                  "item_type": "integer",
+                  "item_optional": false,
+                  "item_default": 0,
+                  "item_title": "XFR rejected requests",
+                  "item_description": "Number of XFR requests per zone name rejected by Xfrout"
+                },
+                {
+                  "item_name": "xfrreqdone",
+                  "item_type": "integer",
+                  "item_optional": false,
+                  "item_default": 0,
+                  "item_title": "Requested zone transfers",
+                  "item_description": "Number of requested zone transfers completed per zone name"
+                }
+              ]
+            }
           }
           }
         },
         },
         {
         {

+ 6 - 2
src/lib/python/isc/notify/notify_out.py

@@ -509,10 +509,14 @@ class NotifyOut:
             sock.sendto(render.get_data(), 0, addrinfo)
             sock.sendto(render.get_data(), 0, addrinfo)
             # count notifying by IPv4 or IPv6 for statistics
             # count notifying by IPv4 or IPv6 for statistics
             if zone_notify_info.get_socket().family == socket.AF_INET:
             if zone_notify_info.get_socket().family == socket.AF_INET:
-                self._counters.inc('zones', zone_notify_info.zone_name,
+                self._counters.inc('zones',
+                                   zone_notify_info.zone_class,
+                                   zone_notify_info.zone_name,
                                   'notifyoutv4')
                                   'notifyoutv4')
             elif zone_notify_info.get_socket().family == socket.AF_INET6:
             elif zone_notify_info.get_socket().family == socket.AF_INET6:
-                self._counters.inc('zones', zone_notify_info.zone_name,
+                self._counters.inc('zones',
+                                   zone_notify_info.zone_class,
+                                   zone_notify_info.zone_name,
                                   'notifyoutv6')
                                   'notifyoutv6')
             logger.info(NOTIFY_OUT_SENDING_NOTIFY, AddressFormatter(addrinfo))
             logger.info(NOTIFY_OUT_SENDING_NOTIFY, AddressFormatter(addrinfo))
         except (socket.error, addr.InvalidAddress) as err:
         except (socket.error, addr.InvalidAddress) as err:

+ 12 - 12
src/lib/python/isc/notify/tests/notify_out_test.py

@@ -304,10 +304,10 @@ class TestNotifyOut(unittest.TestCase):
 
 
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv4')
+                          'zones', 'IN', 'example.net.', 'notifyoutv4')
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv6')
+                          'zones', 'IN', 'example.net.', 'notifyoutv6')
 
 
         example_com_info.prepare_notify_out()
         example_com_info.prepare_notify_out()
         ret = self._notify._send_notify_message_udp(example_com_info,
         ret = self._notify._send_notify_message_udp(example_com_info,
@@ -315,38 +315,38 @@ class TestNotifyOut(unittest.TestCase):
         self.assertTrue(ret)
         self.assertTrue(ret)
         self.assertEqual(socket.AF_INET, example_com_info.sock_family)
         self.assertEqual(socket.AF_INET, example_com_info.sock_family)
         self.assertEqual(self._notify._counters.get(
         self.assertEqual(self._notify._counters.get(
-                'zones', 'example.net.', 'notifyoutv4'), 1)
+                'zones', 'IN', 'example.net.', 'notifyoutv4'), 1)
         self.assertEqual(self._notify._counters.get(
         self.assertEqual(self._notify._counters.get(
-                'zones', 'example.net.', 'notifyoutv6'), 0)
+                'zones', 'IN', 'example.net.', 'notifyoutv6'), 0)
 
 
     def test_send_notify_message_udp_ipv6(self):
     def test_send_notify_message_udp_ipv6(self):
         example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
         example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
 
 
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv4')
+                          'zones', 'IN', 'example.net.', 'notifyoutv4')
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv6')
+                          'zones', 'IN', 'example.net.', 'notifyoutv6')
 
 
         ret = self._notify._send_notify_message_udp(example_com_info,
         ret = self._notify._send_notify_message_udp(example_com_info,
                                                     ('2001:db8::53', 53))
                                                     ('2001:db8::53', 53))
         self.assertTrue(ret)
         self.assertTrue(ret)
         self.assertEqual(socket.AF_INET6, example_com_info.sock_family)
         self.assertEqual(socket.AF_INET6, example_com_info.sock_family)
         self.assertEqual(self._notify._counters.get(
         self.assertEqual(self._notify._counters.get(
-                'zones', 'example.net.', 'notifyoutv4'), 0)
+                'zones', 'IN', 'example.net.', 'notifyoutv4'), 0)
         self.assertEqual(self._notify._counters.get(
         self.assertEqual(self._notify._counters.get(
-                'zones', 'example.net.', 'notifyoutv6'), 1)
+                'zones', 'IN', 'example.net.', 'notifyoutv6'), 1)
 
 
     def test_send_notify_message_with_bogus_address(self):
     def test_send_notify_message_with_bogus_address(self):
         example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
         example_com_info = self._notify._notify_infos[('example.net.', 'IN')]
 
 
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv4')
+                          'zones', 'IN', 'example.net.', 'notifyoutv4')
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv6')
+                          'zones', 'IN', 'example.net.', 'notifyoutv6')
 
 
         # As long as the underlying data source validates RDATA this shouldn't
         # As long as the underlying data source validates RDATA this shouldn't
         # happen, but right now it's not actually the case.  Even if the
         # happen, but right now it's not actually the case.  Even if the
@@ -358,10 +358,10 @@ class TestNotifyOut(unittest.TestCase):
 
 
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv4')
+                          'zones', 'IN', 'example.net.', 'notifyoutv4')
         self.assertRaises(isc.cc.data.DataNotFoundError,
         self.assertRaises(isc.cc.data.DataNotFoundError,
                           self._notify._counters.get,
                           self._notify._counters.get,
-                          'zones', 'example.net.', 'notifyoutv4')
+                          'zones', 'IN', 'example.net.', 'notifyoutv4')
 
 
     def test_zone_notify_handler(self):
     def test_zone_notify_handler(self):
         sent_addrs = []
         sent_addrs = []

+ 96 - 60
src/lib/python/isc/statistics/counters.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium.
+# Copyright (C) 2012-2013  Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -81,19 +81,47 @@ def _add_counter(element, spec, identifier):
         return isc.cc.data.find(element, identifier)
         return isc.cc.data.find(element, identifier)
     except isc.cc.data.DataNotFoundError:
     except isc.cc.data.DataNotFoundError:
         pass
         pass
-    # check whether spec and identifier are correct
-    isc.config.find_spec_part(spec, identifier)
-    # examine spec of the top-level item first
-    spec_ = isc.config.find_spec_part(spec, identifier.split('/')[0])
-    if spec_['item_type'] == 'named_set' and \
-            spec_['named_set_item_spec']['item_type'] ==  'map':
-        map_spec = spec_['named_set_item_spec']['map_item_spec']
-        for name in isc.config.spec_name_list(map_spec):
-            spec_ = isc.config.find_spec_part(map_spec, name)
-            id_str = '%s/%s/%s' % \
-                tuple(identifier.split('/')[0:2] + [name])
-            isc.cc.data.set(element, id_str, spec_['item_default'])
-    else:
+
+    # Note: If there is a named_set type item in the statistics spec
+    # and if there are map type items under it, all of items under the
+    # map type item need to be added. For example, we're assuming that
+    # this method is now adding a counter whose identifier is like
+    # dir1/dir2/dir3/counter1. If both of dir1 and dir2 are named_set
+    # types, and if dir3 is a map type, and if counter1, counter2, and
+    # counter3 are defined as items under dir3 by the statistics spec,
+    # this method would add other two counters:
+    #
+    #   dir1/dir2/dir3/counter2
+    #   dir1/dir2/dir3/counter3
+    #
+    # Otherwise this method just adds the only counter
+    # dir1/dir2/dir3/counter1.
+
+    # examine spec from the top-level item and know whether
+    # has_named_set, and check whether spec and identifier are correct
+    pidr = ''
+    has_named_set = False
+    for idr in identifier.split('/'):
+        if len(pidr) > 0:
+            idr = pidr + '/' + idr
+        spec_ = isc.config.find_spec_part(spec, idr)
+        if isc.config.spec_part_is_named_set(spec_):
+            has_named_set = True
+            break
+        pidr = idr
+    # add all elements in map type if has_named_set
+    has_map = False
+    if has_named_set:
+        p_idr = identifier.rsplit('/', 1)[0]
+        p_spec = isc.config.find_spec_part(spec, p_idr)
+        if isc.config.spec_part_is_map(p_spec):
+            has_map = True
+            for name in isc.config.spec_name_list(p_spec['map_item_spec']):
+                idr_ = p_idr + '/' + name
+                spc_ = isc.config.find_spec_part(spec, idr_)
+                isc.cc.data.set(element, idr_, spc_['item_default'])
+    # otherwise add a specific element
+    if not has_map:
         spec_ = isc.config.find_spec_part(spec, identifier)
         spec_ = isc.config.find_spec_part(spec, identifier)
         isc.cc.data.set(element, identifier, spec_['item_default'])
         isc.cc.data.set(element, identifier, spec_['item_default'])
     return isc.cc.data.find(element, identifier)
     return isc.cc.data.find(element, identifier)
@@ -161,30 +189,38 @@ class _Statistics():
         "item_title": "Zone names",
         "item_title": "Zone names",
         "item_description": "Zone names",
         "item_description": "Zone names",
         "named_set_item_spec": {
         "named_set_item_spec": {
-          "item_name": "zonename",
-          "item_type": "map",
+          "item_name": "classname",
+          "item_type": "named_set",
           "item_optional": False,
           "item_optional": False,
           "item_default": {},
           "item_default": {},
-          "item_title": "Zone name",
-          "item_description": "Zone name",
-          "map_item_spec": [
-            {
-              "item_name": "notifyoutv4",
-              "item_type": "integer",
-              "item_optional": False,
-              "item_default": 0,
-              "item_title": "IPv4 notifies",
-              "item_description": "Number of IPv4 notifies per zone name sent out"
-            },
-            {
-              "item_name": "notifyoutv6",
-              "item_type": "integer",
-              "item_optional": False,
-              "item_default": 0,
-              "item_title": "IPv6 notifies",
-              "item_description": "Number of IPv6 notifies per zone name sent out"
-            }
-          ]
+          "item_title": "RR class name",
+          "item_description": "RR class name",
+          "named_set_item_spec": {
+            "item_name": "zonename",
+            "item_type": "map",
+            "item_optional": False,
+            "item_default": {},
+            "item_title": "Zone name",
+            "item_description": "Zone name",
+            "map_item_spec": [
+              {
+                "item_name": "notifyoutv4",
+                "item_type": "integer",
+                "item_optional": False,
+                "item_default": 0,
+                "item_title": "IPv4 notifies",
+                "item_description": "Number of IPv4 notifies per zone name sent out"
+              },
+              {
+                "item_name": "notifyoutv6",
+                "item_type": "integer",
+                "item_optional": False,
+                "item_default": 0,
+                "item_title": "IPv6 notifies",
+                "item_description": "Number of IPv6 notifies per zone name sent out"
+              }
+            ]
+          }
         }
         }
       }
       }
     ]
     ]
@@ -205,20 +241,20 @@ class Counters():
     per-zone counters, a list of counters which can be handled in the
     per-zone counters, a list of counters which can be handled in the
     class are like the following:
     class are like the following:
 
 
-        zones/example.com./notifyoutv4
-        zones/example.com./notifyoutv6
-        zones/example.com./xfrrej
-        zones/example.com./xfrreqdone
-        zones/example.com./soaoutv4
-        zones/example.com./soaoutv6
-        zones/example.com./axfrreqv4
-        zones/example.com./axfrreqv6
-        zones/example.com./ixfrreqv4
-        zones/example.com./ixfrreqv6
-        zones/example.com./xfrsuccess
-        zones/example.com./xfrfail
-        zones/example.com./last_ixfr_duration
-        zones/example.com./last_axfr_duration
+        zones/IN/example.com./notifyoutv4
+        zones/IN/example.com./notifyoutv6
+        zones/IN/example.com./xfrrej
+        zones/IN/example.com./xfrreqdone
+        zones/IN/example.com./soaoutv4
+        zones/IN/example.com./soaoutv6
+        zones/IN/example.com./axfrreqv4
+        zones/IN/example.com./axfrreqv6
+        zones/IN/example.com./ixfrreqv4
+        zones/IN/example.com./ixfrreqv6
+        zones/IN/example.com./xfrsuccess
+        zones/IN/example.com./xfrfail
+        zones/IN/example.com./last_ixfr_duration
+        zones/IN/example.com./last_axfr_duration
         ixfr_running
         ixfr_running
         axfr_running
         axfr_running
         socket/unixdomain/open
         socket/unixdomain/open
@@ -275,8 +311,9 @@ class Counters():
                 isc.config.spec_name_list(self._statistics._spec):
                 isc.config.spec_name_list(self._statistics._spec):
             self._zones_item_list = isc.config.spec_name_list(
             self._zones_item_list = isc.config.spec_name_list(
                 isc.config.find_spec_part(
                 isc.config.find_spec_part(
-                    self._statistics._spec, self._perzone_prefix)\
-                    ['named_set_item_spec']['map_item_spec'])
+                    self._statistics._spec,
+                    '%s/%s/%s' % (self._perzone_prefix,
+                                  '_CLASS_', self._entire_server)))
 
 
     def clear_all(self):
     def clear_all(self):
         """clears all statistics data"""
         """clears all statistics data"""
@@ -387,15 +424,14 @@ class Counters():
         # Start calculation for '_SERVER_' counts
         # Start calculation for '_SERVER_' counts
         zones_spec = isc.config.find_spec_part(self._statistics._spec,
         zones_spec = isc.config.find_spec_part(self._statistics._spec,
                                                self._perzone_prefix)
                                                self._perzone_prefix)
-        zones_attrs = zones_spec['item_default'][self._entire_server]
         zones_data = {}
         zones_data = {}
-        for attr in zones_attrs:
-            id_str = '%s/%s' % (self._entire_server, attr)
-            sum_ = 0
-            for name in zones:
-                if attr in zones[name]:
-                    sum_ += zones[name][attr]
-            _set_counter(zones_data, zones_spec, id_str, sum_)
+        for cls in zones.keys():
+            for zone in zones[cls].keys():
+                for (attr, val) in zones[cls][zone].items():
+                    id_str1 = '%s/%s/%s' % (cls, zone, attr)
+                    id_str2 = '%s/%s/%s' % (cls, self._entire_server, attr)
+                    _set_counter(zones_data, zones_spec, id_str1, val)
+                    _inc_counter(zones_data, zones_spec, id_str2, val)
         # insert entire-server counts
         # insert entire-server counts
         statistics_data[self._perzone_prefix] = dict(
         statistics_data[self._perzone_prefix] = dict(
             statistics_data[self._perzone_prefix],
             statistics_data[self._perzone_prefix],

+ 28 - 15
src/lib/python/isc/statistics/tests/counters_test.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium.
+# Copyright (C) 2012-2013  Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -23,6 +23,7 @@ import imp
 import isc.config
 import isc.config
 
 
 TEST_ZONE_NAME_STR = "example.com."
 TEST_ZONE_NAME_STR = "example.com."
+TEST_ZONE_CLASS_STR = "IN"
 TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
 TESTDATA_SRCDIR = os.getenv("TESTDATASRCDIR")
 
 
 from isc.statistics import counters
 from isc.statistics import counters
@@ -196,7 +197,8 @@ class BaseTestCounters():
     def test_perzone_counters(self):
     def test_perzone_counters(self):
         # for per-zone counters
         # for per-zone counters
         for name in self.counters._zones_item_list:
         for name in self.counters._zones_item_list:
-            args = (self._perzone_prefix, TEST_ZONE_NAME_STR, name)
+            args = (self._perzone_prefix, TEST_ZONE_CLASS_STR,
+                    TEST_ZONE_NAME_STR, name)
             if name.find('last_') == 0 and name.endswith('_duration'):
             if name.find('last_') == 0 and name.endswith('_duration'):
                 self.counters.start_timer(*args)
                 self.counters.start_timer(*args)
                 self.counters.stop_timer(*args)
                 self.counters.stop_timer(*args)
@@ -204,7 +206,8 @@ class BaseTestCounters():
                 sec = self.counters.get(*args)
                 sec = self.counters.get(*args)
                 for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                 for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                     isc.cc.data.set(self._statistics_data,
                     isc.cc.data.set(self._statistics_data,
-                                    '%s/%s/%s' % (args[0], zone_str, name), sec)
+                                    '%s/%s/%s/%s' % (args[0], args[1],
+                                                     zone_str, name), sec)
                 # twice exec stopper, then second is not changed
                 # twice exec stopper, then second is not changed
                 self.counters.stop_timer(*args)
                 self.counters.stop_timer(*args)
                 self.assertEqual(self.counters.get(*args), sec)
                 self.assertEqual(self.counters.get(*args), sec)
@@ -220,7 +223,8 @@ class BaseTestCounters():
                 self.assertEqual(self.counters.get(*args), 2)
                 self.assertEqual(self.counters.get(*args), 2)
                 for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                 for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                     isc.cc.data.set(self._statistics_data,
                     isc.cc.data.set(self._statistics_data,
-                                    '%s/%s/%s' % (args[0], zone_str, name), 2)
+                                    '%s/%s/%s/%s' % (args[0], args[1],
+                                                     zone_str, name), 2)
         self.check_get_statistics()
         self.check_get_statistics()
 
 
     def test_xfrrunning_counters(self):
     def test_xfrrunning_counters(self):
@@ -277,7 +281,8 @@ class BaseTestCounters():
     def test_perzone_zero_counters(self):
     def test_perzone_zero_counters(self):
         # setting all counters to zero
         # setting all counters to zero
         for name in self.counters._zones_item_list:
         for name in self.counters._zones_item_list:
-            args = (self._perzone_prefix, TEST_ZONE_NAME_STR, name)
+            args = (self._perzone_prefix, TEST_ZONE_CLASS_STR,
+                    TEST_ZONE_NAME_STR, name)
             if name.find('last_') == 0 and name.endswith('_duration'):
             if name.find('last_') == 0 and name.endswith('_duration'):
                 zero = 0.0
                 zero = 0.0
             else:
             else:
@@ -286,7 +291,8 @@ class BaseTestCounters():
             self.counters._incdec(*args, step=zero)
             self.counters._incdec(*args, step=zero)
             for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
             for zone_str in (self._entire_server, TEST_ZONE_NAME_STR):
                 isc.cc.data.set(self._statistics_data,
                 isc.cc.data.set(self._statistics_data,
-                                '%s/%s/%s' % (args[0], zone_str, name), zero)
+                                '%s/%s/%s/%s' % (args[0], args[1],
+                                                 zone_str, name), zero)
         self.check_get_statistics()
         self.check_get_statistics()
 
 
     def test_undefined_item(self):
     def test_undefined_item(self):
@@ -352,15 +358,19 @@ class DummyNotifyOut(BaseDummyModule):
 
 
     def inc_counters(self):
     def inc_counters(self):
         """increments counters"""
         """increments counters"""
-        self.counters.inc('zones', TEST_ZONE_NAME_STR, 'notifyoutv4')
-        self.counters.inc('zones', TEST_ZONE_NAME_STR, 'notifyoutv6')
+        self.counters.inc('zones', TEST_ZONE_CLASS_STR,
+                          TEST_ZONE_NAME_STR, 'notifyoutv4')
+        self.counters.inc('zones', TEST_ZONE_CLASS_STR,
+                          TEST_ZONE_NAME_STR, 'notifyoutv6')
 
 
 class DummyXfroutSession(BaseDummyModule):
 class DummyXfroutSession(BaseDummyModule):
     """A dummy class equivalent to XfroutSession in b10-xfrout"""
     """A dummy class equivalent to XfroutSession in b10-xfrout"""
     def inc_counters(self):
     def inc_counters(self):
         """increments counters"""
         """increments counters"""
-        self.counters.inc('zones', TEST_ZONE_NAME_STR, 'xfrreqdone')
-        self.counters.inc('zones', TEST_ZONE_NAME_STR, 'xfrrej')
+        self.counters.inc('zones', TEST_ZONE_CLASS_STR,
+                          TEST_ZONE_NAME_STR, 'xfrreqdone')
+        self.counters.inc('zones', TEST_ZONE_CLASS_STR,
+                          TEST_ZONE_NAME_STR, 'xfrrej')
         self.counters.inc('axfr_running')
         self.counters.inc('axfr_running')
         self.counters.inc('ixfr_running')
         self.counters.inc('ixfr_running')
         self.counters.dec('axfr_running')
         self.counters.dec('axfr_running')
@@ -399,8 +409,10 @@ class TestDummyNotifyOut(unittest.TestCase):
 
 
     def test_counters(self):
     def test_counters(self):
         self.assertEqual(
         self.assertEqual(
-            {'zones': {'_SERVER_': {'notifyoutv4': 1, 'notifyoutv6': 1},
-                       TEST_ZONE_NAME_STR: {'notifyoutv4': 1, 'notifyoutv6': 1}}},
+            {'zones': {TEST_ZONE_CLASS_STR: { '_SERVER_':
+                           {'notifyoutv4': 1, 'notifyoutv6': 1},
+                                              TEST_ZONE_NAME_STR:
+                           {'notifyoutv4': 1, 'notifyoutv6': 1}}}},
             self.notifier.get_counters())
             self.notifier.get_counters())
 
 
 class TestDummyXfroutServer(unittest.TestCase):
 class TestDummyXfroutServer(unittest.TestCase):
@@ -418,13 +430,14 @@ class TestDummyXfroutServer(unittest.TestCase):
         self.assertEqual(
         self.assertEqual(
             {'axfr_running': 0, 'ixfr_running': 0,
             {'axfr_running': 0, 'ixfr_running': 0,
              'socket': {'unixdomain': {'open': 1, 'close': 1}},
              'socket': {'unixdomain': {'open': 1, 'close': 1}},
-             'zones': {'_SERVER_': {'notifyoutv4': 1,
+             'zones': {TEST_ZONE_CLASS_STR: {
+                        '_SERVER_': {'notifyoutv4': 1,
                                     'notifyoutv6': 1,
                                     'notifyoutv6': 1,
                                     'xfrrej': 1, 'xfrreqdone': 1},
                                     'xfrrej': 1, 'xfrreqdone': 1},
-                       TEST_ZONE_NAME_STR: {'notifyoutv4': 1,
+                        TEST_ZONE_NAME_STR: {'notifyoutv4': 1,
                                         'notifyoutv6': 1,
                                         'notifyoutv6': 1,
                                         'xfrrej': 1,
                                         'xfrrej': 1,
-                                        'xfrreqdone': 1}}},
+                                        'xfrreqdone': 1}}}},
             self.xfrout_server.get_counters())
             self.xfrout_server.get_counters())
 
 
 if __name__== "__main__":
 if __name__== "__main__":

+ 53 - 43
src/lib/python/isc/statistics/tests/testdata/test_spec2.spec

@@ -9,56 +9,66 @@
         "item_type": "named_set",
         "item_type": "named_set",
         "item_optional": false,
         "item_optional": false,
         "item_default": {
         "item_default": {
-          "_SERVER_" : {
-            "notifyoutv4" : 0,
-            "notifyoutv6" : 0,
-            "xfrrej" : 0,
-            "xfrreqdone" : 0
+          "IN" : {
+            "_SERVER_" : {
+              "notifyoutv4" : 0,
+              "notifyoutv6" : 0,
+              "xfrrej" : 0,
+              "xfrreqdone" : 0
+            }
           }
           }
         },
         },
         "item_title": "Zone names",
         "item_title": "Zone names",
         "item_description": "Zone names for Xfrout statistics",
         "item_description": "Zone names for Xfrout statistics",
         "named_set_item_spec": {
         "named_set_item_spec": {
-          "item_name": "zonename",
-          "item_type": "map",
+          "item_name": "classname",
+          "item_type": "named_set",
           "item_optional": false,
           "item_optional": false,
           "item_default": {},
           "item_default": {},
-          "item_title": "Zone name",
-          "item_description": "Zone name for Xfrout statistics",
-          "map_item_spec": [
-            {
-              "item_name": "notifyoutv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IPv4 notifies",
-              "item_description": "Number of IPv4 notifies per zone name sent out from Xfrout"
-            },
-            {
-              "item_name": "notifyoutv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IPv6 notifies",
-              "item_description": "Number of IPv6 notifies per zone name sent out from Xfrout"
-            },
-            {
-              "item_name": "xfrrej",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "XFR rejected requests",
-              "item_description": "Number of XFR requests per zone name rejected by Xfrout"
-            },
-            {
-              "item_name": "xfrreqdone",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "Requested zone transfers",
-              "item_description": "Number of requested zone transfers completed per zone name"
-            }
-          ]
+          "item_title": "RR class name",
+          "item_description": "RR class name for Xfrout statistics",
+          "named_set_item_spec": {
+            "item_name": "zonename",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {},
+            "item_title": "Zone name",
+            "item_description": "Zone name for Xfrout statistics",
+            "map_item_spec": [
+              {
+                "item_name": "notifyoutv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IPv4 notifies",
+                "item_description": "Number of IPv4 notifies per zone name sent out from Xfrout"
+              },
+              {
+                "item_name": "notifyoutv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IPv6 notifies",
+                "item_description": "Number of IPv6 notifies per zone name sent out from Xfrout"
+              },
+              {
+                "item_name": "xfrrej",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "XFR rejected requests",
+                "item_description": "Number of XFR requests per zone name rejected by Xfrout"
+              },
+              {
+                "item_name": "xfrreqdone",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "Requested zone transfers",
+                "item_description": "Number of requested zone transfers completed per zone name"
+              }
+            ]
+          }
         }
         }
       },
       },
       {
       {

+ 107 - 97
src/lib/python/isc/statistics/tests/testdata/test_spec3.spec

@@ -10,110 +10,120 @@
         "item_type": "named_set",
         "item_type": "named_set",
         "item_optional": false,
         "item_optional": false,
         "item_default": {
         "item_default": {
-          "_SERVER_" : {
-	    "soaoutv4": 0,
-	    "soaoutv6": 0,
-	    "axfrreqv4": 0,
-	    "axfrreqv6": 0,
-	    "ixfrreqv4": 0,
-	    "ixfrreqv6": 0,
-	    "xfrsuccess": 0,
-	    "xfrfail": 0,
-	    "last_ixfr_duration": 0.0,
-	    "last_axfr_duration": 0.0
+          "IN" : {
+            "_SERVER_" : {
+              "soaoutv4": 0,
+              "soaoutv6": 0,
+              "axfrreqv4": 0,
+              "axfrreqv6": 0,
+              "ixfrreqv4": 0,
+              "ixfrreqv6": 0,
+              "xfrsuccess": 0,
+              "xfrfail": 0,
+              "last_ixfr_duration": 0.0,
+              "last_axfr_duration": 0.0
+            }
           }
           }
         },
         },
         "item_title": "Zone names",
         "item_title": "Zone names",
         "item_description": "Zone names for Xfrout statistics",
         "item_description": "Zone names for Xfrout statistics",
         "named_set_item_spec": {
         "named_set_item_spec": {
-          "item_name": "zonename",
-          "item_type": "map",
+          "item_name": "classname",
+          "item_type": "named_set",
           "item_optional": false,
           "item_optional": false,
           "item_default": {},
           "item_default": {},
-          "item_title": "Zone name",
-          "item_description": "Zone name for Xfrout statistics",
-          "map_item_spec": [
-            {
-              "item_name": "soaoutv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "SOAOutv4",
-              "item_description": "Number of IPv4 SOA queries sent from Xfrin"
-            },
-            {
-              "item_name": "soaoutv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "SOAOutv6",
-              "item_description": "Number of IPv6 SOA queries sent from Xfrin"
-            },
-            {
-              "item_name": "axfrreqv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "AXFRReqv4",
-              "item_description": "Number of IPv4 AXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "axfrreqv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "AXFRReqv6",
-              "item_description": "Number of IPv6 AXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "ixfrreqv4",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IXFRReqv4",
-              "item_description": "Number of IPv4 IXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "ixfrreqv6",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "IXFRReqv6",
-              "item_description": "Number of IPv6 IXFR requests sent from Xfrin"
-            },
-            {
-              "item_name": "xfrsuccess",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "XfrSuccess",
-              "item_description": "Number of zone transfer requests succeeded"
-            },
-            {
-              "item_name": "xfrfail",
-              "item_type": "integer",
-              "item_optional": false,
-              "item_default": 0,
-              "item_title": "XfrFail",
-              "item_description": "Number of zone transfer requests failed"
-            },
-            {
-              "item_name": "last_ixfr_duration",
-              "item_type": "real",
-              "item_optional": false,
-              "item_default": 0.0,
-              "item_title": "Last IXFR duration",
-              "item_description": "Duration of the last IXFR. 0.0 means no successful IXFR done."
-            },
-            {
-              "item_name": "last_axfr_duration",
-              "item_type": "real",
-              "item_optional": false,
-              "item_default": 0.0,
-              "item_title": "Last AXFR duration",
-              "item_description": "Duration of the last AXFR. 0.0 means no successful AXFR done."
-            }
-          ]
+          "item_title": "RR class name",
+          "item_description": "RR class name for Xfrout statistics",
+          "named_set_item_spec": {
+            "item_name": "zonename",
+            "item_type": "map",
+            "item_optional": false,
+            "item_default": {},
+            "item_title": "Zone name",
+            "item_description": "Zone name for Xfrout statistics",
+            "map_item_spec": [
+              {
+                "item_name": "soaoutv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "SOAOutv4",
+                "item_description": "Number of IPv4 SOA queries sent from Xfrin"
+              },
+              {
+                "item_name": "soaoutv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "SOAOutv6",
+                "item_description": "Number of IPv6 SOA queries sent from Xfrin"
+              },
+              {
+                "item_name": "axfrreqv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "AXFRReqv4",
+                "item_description": "Number of IPv4 AXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "axfrreqv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "AXFRReqv6",
+                "item_description": "Number of IPv6 AXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "ixfrreqv4",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IXFRReqv4",
+                "item_description": "Number of IPv4 IXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "ixfrreqv6",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "IXFRReqv6",
+                "item_description": "Number of IPv6 IXFR requests sent from Xfrin"
+              },
+              {
+                "item_name": "xfrsuccess",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "XfrSuccess",
+                "item_description": "Number of zone transfer requests succeeded"
+              },
+              {
+                "item_name": "xfrfail",
+                "item_type": "integer",
+                "item_optional": false,
+                "item_default": 0,
+                "item_title": "XfrFail",
+                "item_description": "Number of zone transfer requests failed"
+              },
+              {
+                "item_name": "last_ixfr_duration",
+                "item_type": "real",
+                "item_optional": false,
+                "item_default": 0.0,
+                "item_title": "Last IXFR duration",
+                "item_description": "Duration of the last IXFR. 0.0 means no successful IXFR done."
+              },
+              {
+                "item_name": "last_axfr_duration",
+                "item_type": "real",
+                "item_optional": false,
+                "item_default": 0.0,
+                "item_title": "Last AXFR duration",
+                "item_description": "Duration of the last AXFR. 0.0 means no successful AXFR done."
+              }
+            ]
+          }
         }
         }
       },
       },
       {
       {

+ 9 - 9
tests/lettuce/features/xfrin_notify_handling.feature

@@ -75,7 +75,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
-    The statistics counters are 0 in category .Xfrout.zones except for the following items
+    The statistics counters are 0 in category .Xfrout.zones.IN except for the following items
       | item_name                | item_value |
       | item_name                | item_value |
       | _SERVER_.notifyoutv6     |          1 |
       | _SERVER_.notifyoutv6     |          1 |
       | _SERVER_.xfrreqdone      |          1 |
       | _SERVER_.xfrreqdone      |          1 |
@@ -100,7 +100,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrin with cmdctl
     When I query statistics zones of bind10 module Xfrin with cmdctl
-    The statistics counters are 0 in category .Xfrin.zones except for the following items
+    The statistics counters are 0 in category .Xfrin.zones.IN except for the following items
       | item_name                       | item_value | min_value |
       | item_name                       | item_value | min_value |
       | _SERVER_.soaoutv6               |          1 |           |
       | _SERVER_.soaoutv6               |          1 |           |
       | _SERVER_.axfrreqv6              |          1 |           |
       | _SERVER_.axfrreqv6              |          1 |           |
@@ -177,7 +177,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
-    The statistics counters are 0 in category .Xfrout.zones except for the following items
+    The statistics counters are 0 in category .Xfrout.zones.IN except for the following items
       | item_name                | item_value |
       | item_name                | item_value |
       | _SERVER_.notifyoutv4     |          1 |
       | _SERVER_.notifyoutv4     |          1 |
       | _SERVER_.xfrreqdone      |          1 |
       | _SERVER_.xfrreqdone      |          1 |
@@ -202,7 +202,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrin with cmdctl
     When I query statistics zones of bind10 module Xfrin with cmdctl
-    The statistics counters are 0 in category .Xfrin.zones except for the following items
+    The statistics counters are 0 in category .Xfrin.zones.IN except for the following items
       | item_name                       | item_value | min_value |
       | item_name                       | item_value | min_value |
       | _SERVER_.soaoutv4               |          1 |           |
       | _SERVER_.soaoutv4               |          1 |           |
       | _SERVER_.axfrreqv4              |          1 |           |
       | _SERVER_.axfrreqv4              |          1 |           |
@@ -282,7 +282,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
-    The statistics counters are 0 in category .Xfrout.zones except for the following items
+    The statistics counters are 0 in category .Xfrout.zones.IN except for the following items
       | item_name                | item_value | min_value | max_value |
       | item_name                | item_value | min_value | max_value |
       | _SERVER_.notifyoutv6     |          1 |           |           |
       | _SERVER_.notifyoutv6     |          1 |           |           |
       | _SERVER_.xfrrej          |            |         1 |         3 |
       | _SERVER_.xfrrej          |            |         1 |         3 |
@@ -310,7 +310,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrin with cmdctl
     When I query statistics zones of bind10 module Xfrin with cmdctl
-    The statistics counters are 0 in category .Xfrin.zones except for the following items
+    The statistics counters are 0 in category .Xfrin.zones.IN except for the following items
       | item_name              | item_value |
       | item_name              | item_value |
       | _SERVER_.soaoutv6      |          1 |
       | _SERVER_.soaoutv6      |          1 |
       | _SERVER_.axfrreqv6     |          1 |
       | _SERVER_.axfrreqv6     |          1 |
@@ -388,7 +388,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
-    The statistics counters are 0 in category .Xfrout.zones except for the following items
+    The statistics counters are 0 in category .Xfrout.zones.IN except for the following items
       | item_name                | item_value | min_value | max_value |
       | item_name                | item_value | min_value | max_value |
       | _SERVER_.notifyoutv4     |          1 |           |           |
       | _SERVER_.notifyoutv4     |          1 |           |           |
       | _SERVER_.xfrrej          |            |         1 |         3 |
       | _SERVER_.xfrrej          |            |         1 |         3 |
@@ -416,7 +416,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrin with cmdctl
     When I query statistics zones of bind10 module Xfrin with cmdctl
-    The statistics counters are 0 in category .Xfrin.zones except for the following items
+    The statistics counters are 0 in category .Xfrin.zones.IN except for the following items
       | item_name              | item_value |
       | item_name              | item_value |
       | _SERVER_.soaoutv4      |          1 |
       | _SERVER_.soaoutv4      |          1 |
       | _SERVER_.axfrreqv4     |          1 |
       | _SERVER_.axfrreqv4     |          1 |
@@ -454,7 +454,7 @@ Feature: Xfrin incoming notify handling
     last bindctl output should not contain "error"
     last bindctl output should not contain "error"
 
 
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
     When I query statistics zones of bind10 module Xfrout with cmdctl port 47804
-    The statistics counters are 0 in category .Xfrout.zones except for the following items
+    The statistics counters are 0 in category .Xfrout.zones.IN except for the following items
       | item_name                | min_value | max_value |
       | item_name                | min_value | max_value |
       | _SERVER_.notifyoutv6     |         1 |	       5 |
       | _SERVER_.notifyoutv6     |         1 |	       5 |
       | example.org..notifyoutv6 |         1 |	       5 |
       | example.org..notifyoutv6 |         1 |	       5 |