Skip to content

[Nexthop][fboss2-dev] Ip in Ip tunnel#1140

Open
hillol-nexthop wants to merge 3 commits intofacebook:mainfrom
nexthop-ai:ip-in-ip-tunnel
Open

[Nexthop][fboss2-dev] Ip in Ip tunnel#1140
hillol-nexthop wants to merge 3 commits intofacebook:mainfrom
nexthop-ai:ip-in-ip-tunnel

Conversation

@hillol-nexthop
Copy link
Copy Markdown
Contributor

@hillol-nexthop hillol-nexthop commented Apr 29, 2026

Pre-submission checklist

  • I've ran the linters locally and fixed lint errors related to the files I modified in this PR. You can install the linters by running pip install -r requirements-dev.txt && pre-commit install
  • pre-commit run

Based on #1091

Summary

Implements fboss2-dev config tunnel ip-in-ip and fboss2-dev delete tunnel ip-in-ip CLI commands for configuring and removing IP-in-IP tunnel attributes on a per-tunnel basis.

Config commands

# Set destination IP (with optional mask)
config tunnel ip-in-ip <tunnel-id> destination <ip> [mask <mask>]

# Set source IP (with optional mask)
config tunnel ip-in-ip <tunnel-id> source <ip> [mask <mask>]

# Set TTL mode (pipe | uniform)
config tunnel ip-in-ip <tunnel-id> ttl-mode <mode>

# Set DSCP mode (pipe | uniform)
config tunnel ip-in-ip <tunnel-id> dscp-mode <mode>

# Set ECN mode (copy | copy_from_outer | disable | limited_copy)
config tunnel ip-in-ip <tunnel-id> ecn-mode <mode>

# Set termination type (p2p | p2mp | mp2p | mp2mp)
config tunnel ip-in-ip <tunnel-id> termination-type <type>

# Set underlay interface ID (integer)
config tunnel ip-in-ip <tunnel-id> underlay-intf-id <int>

# Multiple attributes in one invocation
config tunnel ip-in-ip <tunnel-id> ttl-mode uniform termination-type p2p

# Bare ID auto-creates an empty tunnel
config tunnel ip-in-ip <tunnel-id>

Attribute names and enum values are matched case-insensitively.

Delete commands

# Delete the entire tunnel
delete tunnel ip-in-ip <tunnel-id>

# Reset (unset) one or more optional attributes — leaves the tunnel intact
delete tunnel ip-in-ip <tunnel-id> <attr> [<attr> ...]

Resettable attributes: source, ttl-mode, dscp-mode, ecn-mode, termination-type. Required fields (destination, underlay-intf-id) cannot be reset individually — delete the whole tunnel instead. Deleting a non-existent tunnel is idempotent (returns success).

Implementation Details

  1. Config command hierarchy under fboss/cli/fboss2/commands/config/tunnel/:
    • CmdConfigTunnel — top-level config tunnel subcommand
    • CmdConfigTunnelIpInIpip-in-ip <tunnel-id> selector that accepts attribute key/value pairs in a single invocation
  2. Delete command hierarchy under fboss/cli/fboss2/commands/delete/tunnel/:
    • CmdDeleteTunnel — top-level delete tunnel subcommand
    • CmdDeleteTunnelIpInIpip-in-ip <tunnel-id> [<attr> ...] for whole-tunnel delete or per-attribute reset
  3. Argument validation: IP addresses validated via folly::IPAddress; enum modes validated against thrift enum strings with helpful error messages; mask is reserved as a sub-keyword and rejected as a tunnel ID.
  4. Build: wired into CmdListConfig and CmdSubcommands; CMake and BUCK updated.
  5. Tests:
    • Unit tests (CmdConfigTunnelIpInIpTest.cpp, CmdDeleteTunnelIpInIpTest.cpp): cover all attribute commands, including invalid inputs, case-insensitive parsing, and mask-as-tunnel-ID rejection.
    • Integration tests (ConfigTunnelIpInIpTest.cpp, DeleteTunnelIpInIpTest.cpp): end-to-end set/verify of multi-attribute config, auto-create, full-tunnel delete, idempotent delete, and per-attribute reset against a live agent.

Test Plan

Unit and integration tests pass.

Note: Google Test filter = TunnelIpInIpTest.*
[==========] Running 7 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 7 tests from TunnelIpInIpTest
[ RUN      ] TunnelIpInIpTest.CreateCompleteProductionTunnel
[       OK ] TunnelIpInIpTest.CreateCompleteProductionTunnel (111 ms)
[ RUN      ] TunnelIpInIpTest.SetUnderlayIntfIdInvalidRejected
[       OK ] TunnelIpInIpTest.SetUnderlayIntfIdInvalidRejected (119 ms)
[ RUN      ] TunnelIpInIpTest.DeleteCompleteProductionTunnel
[       OK ] TunnelIpInIpTest.DeleteCompleteProductionTunnel (125 ms)
[ RUN      ] TunnelIpInIpTest.ResetOptionalAttrsOnCompleteTunnel
[       OK ] TunnelIpInIpTest.ResetOptionalAttrsOnCompleteTunnel (159 ms)
[ RUN      ] TunnelIpInIpTest.DeleteNonExistentIsIdempotent
[       OK ] TunnelIpInIpTest.DeleteNonExistentIsIdempotent (13 ms)
[ RUN      ] TunnelIpInIpTest.ResetRequiredFieldRejected
[       OK ] TunnelIpInIpTest.ResetRequiredFieldRejected (104 ms)
[ RUN      ] TunnelIpInIpTest.UnknownAttrRejected
[       OK ] TunnelIpInIpTest.UnknownAttrRejected (167 ms)
[----------] 7 tests from TunnelIpInIpTest (801 ms total)

[----------] Global test environment tear-down
[==========] 7 tests from 1 test suite ran. (801 ms total)
[  PASSED  ] 7 tests.

# Summary

Adds a `VlanManager` class that auto-creates a VLAN (and its required
`cfg::Interface`) in the session config whenever a `config vlan <id>`
subcommand references a VLAN that does not yet exist.

Previously, `config vlan <id> static-mac add` and
`config vlan <id> port taggingMode` would throw an error if the VLAN
was not already present in the running config, forcing operators to
create the VLAN manually first. Now these commands create the VLAN
on demand and print a one-line notice when they do:

```
Created VLAN <id>
```

The agent requires every VLAN to have a matching `cfg::Interface` entry
or it rejects the commit. `VlanManager::createVlan` therefore creates
both objects atomically:
- `cfg::Vlan` with `id`, `name = "Vlan<id>"`, `routable = false`
- `cfg::Interface` with `intfID = id`, `vlanID = id`,
  `name = "fboss<id>"`, `routerID = 0`, `ipAddresses = []`

For `static-mac delete` on a non-existent VLAN the command now returns
an idempotent "does not exist" message instead of throwing, consistent
with the delete-on-non-existent pattern used elsewhere.

Also fixes a latent bug in `ConfigSession::saveConfig` where a `CHECK`
would fatally abort when run in a test context with no CLI arguments on
the process command line. The inline comment already described the
correct behaviour as "gracefully skip"; the CHECK is removed to match.

# Test Plan

Unit tests (`fboss2_cmd_config_test --gtest_filter='VlanManager*'`):

```
[==========] Running 12 tests from 1 test suite.
[----------] 12 tests from VlanManagerTestFixture
[ RUN      ] VlanManagerTestFixture.createVlanNewVlan
[       OK ] VlanManagerTestFixture.createVlanNewVlan (44 ms)
[ RUN      ] VlanManagerTestFixture.createVlanAlreadyExists
[       OK ] VlanManagerTestFixture.createVlanAlreadyExists (40 ms)
[ RUN      ] VlanManagerTestFixture.createVlanSetsCorrectId
[       OK ] VlanManagerTestFixture.createVlanSetsCorrectId (40 ms)
[ RUN      ] VlanManagerTestFixture.createVlanSetsAutoGeneratedName
[       OK ] VlanManagerTestFixture.createVlanSetsAutoGeneratedName (49 ms)
[ RUN      ] VlanManagerTestFixture.createVlanSetsRoutableFalse
[       OK ] VlanManagerTestFixture.createVlanSetsRoutableFalse (44 ms)
[ RUN      ] VlanManagerTestFixture.createVlanDoesNotSaveConfig
[       OK ] VlanManagerTestFixture.createVlanDoesNotSaveConfig (45 ms)
[ RUN      ] VlanManagerTestFixture.createVlanAlsoCreatesInterface
[       OK ] VlanManagerTestFixture.createVlanAlsoCreatesInterface (45 ms)
[ RUN      ] VlanManagerTestFixture.createVlanDoesNotDuplicateInterface
[       OK ] VlanManagerTestFixture.createVlanDoesNotDuplicateInterface (37 ms)
[ RUN      ] VlanManagerTestFixture.getOrCreateVlanReturnsExistingVlan
[       OK ] VlanManagerTestFixture.getOrCreateVlanReturnsExistingVlan (41 ms)
[ RUN      ] VlanManagerTestFixture.getOrCreateVlanCreatesNewVlan
Created VLAN 777
[       OK ] VlanManagerTestFixture.getOrCreateVlanCreatesNewVlan (40 ms)
[ RUN      ] VlanManagerTestFixture.getOrCreateVlanPrintsMessageForNewVlan
[       OK ] VlanManagerTestFixture.getOrCreateVlanPrintsMessageForNewVlan (37 ms)
[ RUN      ] VlanManagerTestFixture.getOrCreateVlanNoPrintForExistingVlan
[       OK ] VlanManagerTestFixture.getOrCreateVlanNoPrintForExistingVlan (40 ms)
[----------] 12 tests from VlanManagerTestFixture (508 ms total)
[  PASSED  ] 12 tests.
```

End-to-end integration tests on minipack3
(`fboss2_integration_test --gtest_filter='ConfigVlanStaticMacTest.*'`):

```
[==========] Running 3 tests from 1 test suite.
[----------] 3 tests from ConfigVlanStaticMacTest
[ RUN      ] ConfigVlanStaticMacTest.StaticMacAddDeleteOnExistingVlan
[       OK ] ConfigVlanStaticMacTest.StaticMacAddDeleteOnExistingVlan (111 ms)
[ RUN      ] ConfigVlanStaticMacTest.AutoCreateVlanInSession
[       OK ] ConfigVlanStaticMacTest.AutoCreateVlanInSession (133 ms)
[ RUN      ] ConfigVlanStaticMacTest.DeleteOnNonExistentVlanIsIdempotent
[       OK ] ConfigVlanStaticMacTest.DeleteOnNonExistentVlanIsIdempotent (11 ms)
[----------] 3 tests from ConfigVlanStaticMacTest (256 ms total)
[  PASSED  ] 3 tests.
```

## Sample usage

Add a static MAC to a brand-new VLAN — the CLI creates both the VLAN
and its interface automatically, then shows the diff before committing:

```
$ fboss2 config vlan 3998 static-mac add AA:BB:CC:DD:EE:FF eth1/1/1
Created VLAN 3998
Successfully added static MAC entry: MAC AA:BB:CC:DD:EE:FF -> VLAN 3998, Port eth1/1/1 (ID 9)

$ fboss2 config session diff
--- current live config
+++ session config
@@ -2168,6 +2168,17 @@
+      {
+        "intfID": 3998,
+        "ipAddresses": [],
+        "name": "fboss3998",
+        "routerID": 0,
+        "vlanID": 3998
+      }
@@ -5899,6 +5910,11 @@
+      {
+        "egressLogicalPortID": 9,
+        "macAddress": "AA:BB:CC:DD:EE:FF",
+        "vlanID": 3998
+      }
@@ -7779,6 +7795,13 @@
+      {
+        "id": 3998,
+        "name": "Vlan3998",
+        "routable": false
+      }
```

Delete on a non-existent VLAN is idempotent (no VLAN is created):

```
$ fboss2 config vlan 9999 static-mac delete AA:BB:CC:DD:EE:FF
Static MAC entry for MAC AA:BB:CC:DD:EE:FF on VLAN 9999 does not exist
```
@meta-cla meta-cla Bot added the CLA Signed label Apr 29, 2026
@hillol-nexthop hillol-nexthop changed the title Ip in ip tunnel [Nexthop][fboss2-dev] Ip in Ip tunnel Apr 29, 2026
Adds 'fboss2-dev config tunnel ip-in-ip' and 'delete tunnel ip-in-ip'
along with the supporting session/handler plumbing:

- New command tree under commands/config/tunnel/ip_in_ip and
  commands/delete/tunnel/ip_in_ip for create / per-attribute update /
  whole-tunnel delete / per-attribute reset.
- ConfigSession: drop pre-commit underlay-intf-id validation (defer to
  agent), fix EPERM when metadata file is root-owned.
- VlanManager-driven underlay setup in integration tests, replacing the
  crash-prone probe.
- Integration tests (TunnelIpInIpTest.cpp): single fixture covering the
  full positive + negative matrix for both config and delete, with
  fixture-level auto-cleanup. Drops the duplicated Config/Delete files
  and the obsolete ConfigSessionRestart / ConfigInterfaceSpeed tests.
- Unit tests under test/config for the new command handlers.
- Misc: clang-tidy include cleanup (IPAddressV6.h).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hillol-nexthop hillol-nexthop marked this pull request as ready for review April 29, 2026 12:58
@hillol-nexthop hillol-nexthop requested review from a team as code owners April 29, 2026 12:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants