Skip to content

Commit

Permalink
interface: implement VLAN subinterfaces configuration
Browse files Browse the repository at this point in the history
Example configuration (CLI):
```
[snip]
interfaces interface eth-rt2.10
 type ietf-if-extensions:ethSubInterface
 encapsulation dot1q-vlan outer-tag vlan-id 10
 parent-interface eth-rt2
!
```

Example configuration (JSON):
```
{
  "ietf-interfaces:interfaces": {
    "interface": [
      [snip]
      {
        "name": "eth-rt2.10",
        "type": "ietf-if-extensions:ethSubInterface",
        "ietf-if-extensions:encapsulation": {
          "ietf-if-vlan-encapsulation:dot1q-vlan": {
            "outer-tag": {
              "vlan-id": 10
            }
          }
        },
        "ietf-if-extensions:parent-interface": "eth-rt2"
      }
    ]
  }
}
```

Signed-off-by: Renato Westphal <[email protected]>
  • Loading branch information
rwestphal committed Apr 16, 2024
1 parent 5634dce commit 18a7f40
Show file tree
Hide file tree
Showing 12 changed files with 1,862 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ Holo supports the following IETF RFCs and Internet drafts:
| ietf-bfd@2022-09-22 | 100.00% | 100.00% | - | - | [100.00%](http://westphal.com.br/holo/ietf-bfd.html) |
| ietf-bgp-policy@2023-07-05 | 100.00% | - | - | - | [100.00%](http://westphal.com.br/holo/ietf-bgp-policy.html) |
| ietf-bgp@2023-07-05 | 32.38% | 87.86% | - | - | [61.39%](http://westphal.com.br/holo/ietf-bgp.html) |
| ietf-if-extensions@2023-01-26 | 100.00% | 0.00% | - | - | [50.00%](http://westphal.com.br/holo/ietf-if-extensions.html) |
| ietf-if-vlan-encapsulation@2023-01-26 | 42.86% | - | - | - | [42.86%](http://westphal.com.br/holo/ietf-if-vlan-encapsulation.html) |
| ietf-interfaces@2018-01-09 | 100.00% | 0.00% | - | - | [22.22%](http://westphal.com.br/holo/ietf-interfaces.html) |
| ietf-ip@2018-01-09 | 52.17% | 0.00% | - | - | [40.00%](http://westphal.com.br/holo/ietf-ip.html) |
| ietf-ipv4-unicast-routing@2018-03-13 | 100.00% | 100.00% | - | - | [100.00%](http://westphal.com.br/holo/ietf-ipv4-unicast-routing.html) |
Expand Down
21 changes: 20 additions & 1 deletion holo-interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl Interface {
&self,
ifindex: u32,
netlink_handle: &rtnetlink::Handle,
interfaces: &Interfaces,
) {
// Set administrative status.
netlink::admin_status_change(
Expand All @@ -74,6 +75,22 @@ impl Interface {
)
.await;

// Create VLAN subinterface.
if let Some(vlan_id) = self.config.vlan_id
&& self.ifindex.is_none()
&& let Some(parent) = &self.config.parent
&& let Some(parent) = interfaces.get_by_name(parent)
&& let Some(parent_ifindex) = parent.ifindex
{
netlink::vlan_create(
netlink_handle,
self.name.clone(),
parent_ifindex,
vlan_id,
)
.await;
}

// Set MTU.
if let Some(mtu) = self.config.mtu {
netlink::mtu_change(netlink_handle, ifindex, mtu).await;
Expand Down Expand Up @@ -153,7 +170,9 @@ impl Interfaces {
// configuration options.
if iface.ifindex.is_none() {
iface.ifindex = Some(ifindex);
iface.apply_config(ifindex, netlink_handle).await;

let iface = &self.arena[iface_idx];
iface.apply_config(ifindex, netlink_handle, self).await;
}
}
None => {
Expand Down
15 changes: 15 additions & 0 deletions holo-interface/src/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,21 @@ pub(crate) async fn mtu_change(handle: &Handle, ifindex: u32, mtu: u32) {
}
}

pub(crate) async fn vlan_create(
handle: &Handle,
name: String,
parent_ifindex: u32,
vlan_id: u16,
) {
// Create netlink request.
let request = handle.link().add().vlan(name, parent_ifindex, vlan_id);

// Execute request.
if let Err(error) = request.execute().await {
error!(%parent_ifindex, %vlan_id, %error, "failed to create VLAN interface");
}
}

pub(crate) async fn addr_install(
handle: &Handle,
ifindex: u32,
Expand Down
48 changes: 48 additions & 0 deletions holo-interface/src/northbound/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ pub enum Event {
InterfaceDelete(String),
AdminStatusChange(String, bool),
MtuChange(String, u32),
VlanCreate(String, u16),
AddressInstall(String, IpNetwork),
AddressUninstall(String, IpNetwork),
}
Expand All @@ -51,6 +52,8 @@ pub enum Event {
pub struct InterfaceCfg {
pub enabled: bool,
pub mtu: Option<u32>,
pub parent: Option<String>,
pub vlan_id: Option<u16>,
pub addr_list: BTreeSet<IpNetwork>,
}

Expand Down Expand Up @@ -96,6 +99,31 @@ fn load_callbacks() -> Callbacks<Master> {
let event_queue = args.event_queue;
event_queue.insert(Event::AdminStatusChange(ifname, enabled));
})
.path(interfaces::interface::parent_interface::PATH)
.modify_apply(|master, args| {
let ifname = args.list_entry.into_interface().unwrap();
let parent = args.dnode.get_string();

let iface = master.interfaces.get_mut_by_name(&ifname).unwrap();
iface.config.parent = Some(parent);
})
.delete_apply(|master, args| {
let ifname = args.list_entry.into_interface().unwrap();

let iface = master.interfaces.get_mut_by_name(&ifname).unwrap();
iface.config.parent = None;
})
.path(interfaces::interface::encapsulation::dot1q_vlan::outer_tag::vlan_id::PATH)
.modify_apply(|master, args| {
let ifname = args.list_entry.into_interface().unwrap();
let vlan_id = args.dnode.get_u16();

let iface = master.interfaces.get_mut_by_name(&ifname).unwrap();
iface.config.vlan_id = Some(vlan_id);

let event_queue = args.event_queue;
event_queue.insert(Event::VlanCreate(ifname, vlan_id));
})
.path(interfaces::interface::ipv4::PATH)
.create_apply(|_context, _args| {
// TODO: implement me!
Expand Down Expand Up @@ -288,6 +316,24 @@ impl Provider for Master {
.await;
}
}
Event::VlanCreate(ifname, vlan_id) => {
// If the parent interface is active, create VLAN subinterface
// using the netlink handle.
if let Some(iface) = self.interfaces.get_by_name(&ifname)
&& iface.ifindex.is_none()
&& let Some(parent) = &iface.config.parent
&& let Some(parent) = self.interfaces.get_by_name(parent)
&& let Some(parent_ifindex) = parent.ifindex
{
netlink::vlan_create(
&self.netlink_handle,
iface.name.clone(),
parent_ifindex,
vlan_id,
)
.await;
}
}
Event::AddressInstall(ifname, addr) => {
// If the interface is active, install the address using the
// netlink handle.
Expand Down Expand Up @@ -325,6 +371,8 @@ impl Default for InterfaceCfg {
InterfaceCfg {
enabled,
mtu: None,
parent: None,
vlan_id: None,
addr_list: Default::default(),
}
}
Expand Down
7 changes: 6 additions & 1 deletion holo-interface/src/northbound/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@ use crate::Master;

impl ProviderBase for Master {
fn yang_modules() -> &'static [&'static str] {
&["ietf-interfaces", "ietf-ip"]
&[
"ietf-if-extensions",
"ietf-if-vlan-encapsulation",
"ietf-interfaces",
"ietf-ip",
]
}

fn top_level_node(&self) -> String {
Expand Down
2 changes: 2 additions & 0 deletions holo-tools/yang-coverage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

cargo run --bin yang_coverage --\
-m ietf-interfaces\
-m ietf-if-extensions\
-m ietf-if-vlan-encapsulation\
-m ietf-ip\
-m ietf-ipv4-unicast-routing\
-m ietf-ipv6-unicast-routing\
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module ietf-if-extensions-holo-deviations {
yang-version 1.1;
namespace "http://holo-routing.org/yang/ietf-if-extensions-holo-deviations";
prefix ietf-if-extensions-holo-deviations;

import ietf-interfaces {
prefix if;
}

import ietf-if-extensions {
prefix if-ext;
}

organization
"Holo Routing Stack";

description
"This module defines deviation statements for the ietf-if-extensions
module.";

deviation "/if:interfaces/if:interface/if:statistics/if-ext:in-discard-unknown-encaps" {
deviate not-supported;
}

deviation "/if:interfaces/if:interface/if-ext:forwarding-mode" {
deviate not-supported;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module ietf-if-vlan-encapsulation-holo-deviations {
yang-version 1.1;
namespace "http://holo-routing.org/yang/ietf-if-vlan-encapsulation-holo-deviations";
prefix ietf-if-vlan-encapsulation-holo-deviations;

import ietf-interfaces {
prefix if;
}

import ietf-if-extensions {
prefix if-ext;
}

import ietf-if-vlan-encapsulation {
prefix if-vlan;
}

organization
"Holo Routing Stack";

description
"This module defines deviation statements for the ietf-if-vlan-encapsulation
module.";

deviation "/if:interfaces/if:interface/if-ext:encapsulation/if-ext:encaps-type/if-vlan:dot1q-vlan/if-vlan:dot1q-vlan/if-vlan:outer-tag" {
deviate delete {
must 'tag-type = "dot1q-types:s-vlan" or '
+ 'tag-type = "dot1q-types:c-vlan"';
}
}

deviation "/if:interfaces/if:interface/if-ext:encapsulation/if-ext:encaps-type/if-vlan:dot1q-vlan/if-vlan:dot1q-vlan/if-vlan:outer-tag/if-vlan:tag-type" {
deviate not-supported;
}

deviation "/if:interfaces/if:interface/if-ext:encapsulation/if-ext:encaps-type/if-vlan:dot1q-vlan/if-vlan:dot1q-vlan/if-vlan:second-tag" {
deviate not-supported;
}

/*
deviation "/if:interfaces/if:interface/if-ext:encapsulation/if-ext:encaps-type/if-vlan:dot1q-vlan/if-vlan:dot1q-vlan/if-vlan:second-tag/if-vlan:tag-type" {
deviate not-supported;
}
*/

/*
deviation "/if:interfaces/if:interface/if-ext:encapsulation/if-ext:encaps-type/if-vlan:dot1q-vlan/if-vlan:dot1q-vlan/if-vlan:second-tag/if-vlan:vlan-id" {
deviate not-supported;
}
*/
}
Loading

0 comments on commit 18a7f40

Please sign in to comment.