<?xml version="1.0"?>
<!-- A Relax NG schema for network interfaces -->
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
         xmlns:v="http://netcf.org/xml/version/1.0"
         datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
  <!-- Versions for this schema are simple integers that are incremented
       everytime a changed (but backwards compatible) version
       is released. The current version is indicated with the v:serial
       attribute on the start element.
  -->
  <start v:serial="4">
    <choice>
      <ref name="ethernet-interface"/>
      <ref name="bridge-interface"/>
      <ref name="bond-interface"/>
      <ref name="vlan-interface"/>
    </choice>
  </start>

  <include href='basictypes.rng'/>
  <!--
       FIXME: How do we handle VLAN's ? Should they be their own interface
       or should we treat them as an option on the base interface ?  For
       example, for vlan eth0.42, it would make sense to make that part of
       the definition of the eth0 interface.
  -->

  <!--
       Ethernet adapter
  -->
  <define name="basic-ethernet-content">
    <attribute name="type">
      <value>ethernet</value>
    </attribute>
    <ref name="name-attr"/>
    <!-- If no MAC is given when the interface is defined, it is determined
         by using the device name.
         FIXME: What if device name and MAC don't specify the same NIC ? -->
    <optional>
      <element name="mac">
        <attribute name="address"><ref name="macAddr"/></attribute>
      </element>
    </optional>
    <!-- FIXME: Allow (some) ethtool options -->
  </define>

  <!-- Ethernet adapter without IP addressing, e.g. for a bridge -->
  <define name="bare-ethernet-interface">
    <element name="interface">
      <ref name="basic-ethernet-content"/>
    </element>
  </define>

  <define name="ethernet-interface">
    <element name="interface">
      <ref name="startmode"/>
      <ref name="basic-ethernet-content"/>
      <ref name="mtu"/>
      <ref name="interface-addressing"/>
    </element>
  </define>

  <!--
      VLAN's
  -->
  <define name="vlan-interface-common">
    <attribute name="type">
      <value>vlan</value>
    </attribute>
    <!-- The name attribute is only useful for reporting back and is always
         of the form DEVICE.VLAN
    -->
    <optional><ref name="name-attr"/></optional>
  </define>

  <define name="vlan-device">
    <element name="vlan">
      <attribute name="tag"><ref name="vlan-id"/></attribute>
      <element name="interface">
        <attribute name="name"><ref name="deviceName"/></attribute>
      </element>
    </element>
  </define>

  <define name="bare-vlan-interface">
    <element name="interface">
      <ref name="vlan-interface-common"/>
      <ref name="vlan-device"/>
    </element>
  </define>

  <define name="vlan-interface">
    <element name="interface">
      <ref name="vlan-interface-common"/>
      <ref name="startmode"/>
      <ref name="mtu"/>
      <ref name="interface-addressing"/>
      <ref name="vlan-device"/>
    </element>
  </define>

  <!--
       Bridges
  -->
  <define name="bridge-interface">
    <element name="interface">
      <attribute name="type">
        <value>bridge</value>
      </attribute>
      <ref name="name-attr"/>
      <ref name="startmode"/>
      <ref name="mtu"/>
      <ref name="interface-addressing"/>
      <element name="bridge">
        <optional>
          <attribute name="stp">
            <ref name="on-or-off"/>
          </attribute>
        </optional>
        <!-- Bridge forward delay (see 'brctl setfd') -->
        <optional v:since="2">
          <attribute name="delay"><ref name="timeval"/></attribute>
        </optional>
        <zeroOrMore>
          <choice>
            <ref name="bare-ethernet-interface"/>
            <ref name="bare-vlan-interface"/>
            <ref v:since="2" name="bare-bond-interface"/>
          </choice>
        </zeroOrMore>
      </element>
    </element>
  </define>
  <!-- Jim Fehlig would like support for other bridge attributes, in
       particular hellotime, forwarddelay, and maxage
  -->

  <!--
      Bonds
  -->
  <define name="bond-interface-common">
    <attribute name="type">
      <value>bond</value>
    </attribute>
    <ref name="name-attr"/>
  </define>

  <define name="bond-element">
    <element name="bond">
      <optional>
        <attribute name="mode">
          <choice>
            <value>balance-rr</value>
            <!-- The primary interface is the first interface child
                 of the bond element -->
            <value>active-backup</value>
            <value>balance-xor</value>
            <value>broadcast</value>
            <value>802.3ad</value>
            <value>balance-tlb</value>
            <value>balance-alb</value>
          </choice>
        </attribute>
      </optional>

      <!-- FIXME: add more attributes

           mode == 802.3ad
             ad_select
             lacp_rate
             xmit_hash_policy

           mode == active-backup
             fail_over_mac
             num_grat_arp when mode == active-backup (since 3.3.0)
             num_unsol_na when mode == active-backup (ipv6, since 3.4.0)

           mode == balance-xor
             xmit_hash_policy       (since 2.6.3/3.2.2)
      -->

      <optional>
        <choice>
          <element name="miimon">
            <!-- miimon frequency in ms -->
            <attribute name="freq"><ref name="uint"/></attribute>
            <optional>
              <attribute name="downdelay"><ref name="uint"/></attribute>
            </optional>
            <optional>
              <attribute name="updelay"><ref name="uint"/></attribute>
            </optional>
            <optional>
              <!-- use_carrier -->
              <attribute name="carrier">
                <choice>
                  <!-- use MII/ETHTOOL ioctl -->
                  <value>ioctl</value>
                  <!-- use netif_carrier_ok() -->
                  <value>netif</value>
                </choice>
              </attribute>
            </optional>
          </element>
          <element name="arpmon">
            <attribute name="interval"><ref name="uint"/></attribute>
            <attribute name="target"><ref name="ipv4Addr"/></attribute>
            <optional>
              <attribute name="validate">
                <choice>
                  <value>none</value>
                  <value>active</value>
                  <value>backup</value>
                  <value>all</value>
                </choice>
              </attribute>
            </optional>
          </element>
        </choice>
      </optional>

      <oneOrMore>
        <!-- The slave interfaces -->
        <ref name="bare-ethernet-interface"/>
      </oneOrMore>
    </element>
  </define>

  <define name="bare-bond-interface">
    <element name="interface">
      <ref name="bond-interface-common"/>
      <ref name="bond-element"/>
    </element>
  </define>

  <define name="bond-interface">
    <element name="interface">
      <ref name="bond-interface-common"/>
      <ref name="startmode"/>
      <ref name="mtu"/>
      <ref name="interface-addressing"/>
      <ref name="bond-element"/>
    </element>
  </define>

  <!-- Basic attributes for all interface types -->
  <define name="name-attr">
    <!-- The device name, like eth0 or br2 -->
    <attribute name="name"><ref name="deviceName"/></attribute>
  </define>

  <define name="mtu">
    <optional>
      <element name="mtu">
        <attribute name="size"><ref name="uint"/></attribute>
      </element>
    </optional>
  </define>

  <define name="startmode">
    <element name="start">
      <attribute name="mode">
        <choice>
          <value>onboot</value>
          <value>none</value>
          <value>hotplug</value>
          <!-- Jim Fehlig lists the following that SuSe supports:
               manual, ifplug, nfsroot -->
        </choice>
      </attribute>
    </element>
  </define>

  <!--
       Assignment of addresses to an interface, allowing for
       different protocols
  -->
  <define name="interface-addressing">
    <choice>
      <group>
        <optional>
          <ref name="protocol-ipv4"/>
        </optional>
        <optional v:since="3">
          <ref name="protocol-ipv6"/>
        </optional>
      </group>
      <group>
        <optional v:since="3">
          <ref name="protocol-ipv6"/>
        </optional>
        <optional>
          <ref name="protocol-ipv4"/>
        </optional>
      </group>
    </choice>
  </define>

  <define name="protocol-ipv4">
    <element name="protocol">
      <attribute name="family">
        <value>ipv4</value>
      </attribute>
      <choice>
        <ref name="dhcp-element"/>
        <group>
          <element name="ip">
            <attribute name="address"><ref name="ipv4Addr"/></attribute>
            <optional>
              <attribute name="prefix"><ref name="ipv4Prefix"/></attribute>
            </optional>
          </element>
          <optional>
            <element name="route">
              <attribute name="gateway"><ref name="ipv4Addr"/></attribute>
            </element>
          </optional>
        </group>
      </choice>
    </element>
  </define>

  <define name="protocol-ipv6">
    <element name="protocol">
      <attribute name="family">
        <value>ipv6</value>
      </attribute>
      <optional>
        <element name="autoconf"><empty/></element>
      </optional>
      <optional>
        <ref name="dhcp-element"/>
      </optional>
      <zeroOrMore>
        <element name="ip">
          <attribute name="address"><ref name="ipv6Addr"/></attribute>
          <optional>
            <attribute name="prefix"><ref name="ipv6Prefix"/></attribute>
          </optional>
        </element>
      </zeroOrMore>
      <optional>
        <element name="route">
          <attribute name="gateway"><ref name="ipv6Addr"/></attribute>
        </element>
      </optional>
    </element>
  </define>

  <define name="dhcp-element">
    <element name="dhcp">
      <optional>
        <attribute name="peerdns">
          <ref name="yes-or-no"/>
        </attribute>
      </optional>
    </element>
  </define>

  <!-- Jim Fehlig (<jfehlig@novell.com>) suggest the
       following additions to DHCP:

       WRT dhcp element, would it make sense to consider hostname (hostname
       to send to server) and if to change the local hostname to the
       hostname delivered via dhcp?  E.g.  hostname="foo" (default
       `hostname`) sethostname

       Also route:
         setrouting (default "yes")
         setdefaultroute (default "yes")

       and NIS:
         nis (default "yes")
         setnisdomain (default "yes")

       What about dhcpv6?  A separate <dhcp6 /> element?
  -->

  <!-- Jim Fehlig suggest adding static routing info

       As for routing info, how about a separate route element:

       <route gateway="192.168.0.1" /> # destination=default
       <route destination="default" gateway="192.168.0.1" />
       <route destination="10.0.0.0/8" gateway="192.168.0.2" />
       <route destination="2001:DB8:C::/64" gateway="2001:DB8:C::1" />
       <route destination="2001:DB8::/32"> # unrecheable route (loopback)

       It would perhaps make sense to use iproute2 names, that is prefix
       instead of destination and nexthop instead of gateway.
  -->

  <!-- Auxiliary definitions -->
  <define name="on-or-off">
    <choice>
      <value>on</value>
      <value>off</value>
    </choice>
  </define>

  <define name="yes-or-no">
    <choice>
      <value>yes</value>
      <value>no</value>
    </choice>
  </define>

  <!-- Type library -->

  <define name='uint'>
    <data type='unsignedInt'>
      <param name="pattern">[0-9]+</param>
    </data>
  </define>

  <define name="timeval">
    <data type="double">
      <param name="minInclusive">0</param>
    </data>
  </define>

  <define name='vlan-id'>
    <data type="unsignedInt">
      <param name="maxInclusive">4096</param>
    </data>
  </define>
</grammar>
