@@ -691,6 +691,69 @@ def _set_yang_area_attrs(router, protocol_type, area_id, attrs):
691691 router .vtysh_cmd ("\n " .join (lines ))
692692
693693
694+ def test_ospf_distance_cli_routes_through_yang ():
695+ """The legacy single-value `distance N` / `no distance` and multi-value
696+ `distance ospf intra-area X inter-area Y external Z` / `no distance ospf`
697+ forms continue to work via vtysh but now route through the ietf-ospf
698+ YANG `/preference/all` and `/preference/{intra-area,inter-area,external}`
699+ leaves. Verify by issuing the legacy CLI and confirming the daemon's
700+ running-config reflects the change exactly as before.
701+
702+ The OSPFv3 path is covered indirectly by test_ospf_yang_preference_config;
703+ legacy `distance` invocations in OSPF6_NODE additionally trigger
704+ ospf6_restart_spf, which trips a pre-existing ospf6_route_remove_all
705+ use-after-free when the route table is populated, so this test sticks
706+ to OSPFv2 for the legacy CLI."""
707+ tgen = get_topogen ()
708+ if tgen .routers_have_failure ():
709+ pytest .skip ("skipped because of router(s) failure" )
710+
711+ r1 = tgen .gears ["r1" ]
712+ daemon = "ospfd"
713+ router_block = "router ospf"
714+ cli_proto = "ospf"
715+
716+ # single-value scope (preference/all)
717+ r1 .vtysh_cmd (
718+ "configure terminal\n " "{}\n " " distance 137\n " .format (router_block )
719+ )
720+ running = r1 .vtysh_cmd ("show running-config {}" .format (daemon ))
721+ assert " distance 137" in running , running
722+
723+ r1 .vtysh_cmd (
724+ "configure terminal\n " "{}\n " " no distance\n " .format (router_block )
725+ )
726+ running = r1 .vtysh_cmd ("show running-config {}" .format (daemon ))
727+ assert "distance 137" not in running , running
728+
729+ # multi-value scope (preference/intra-area + /inter-area + /external)
730+ r1 .vtysh_cmd (
731+ "configure terminal\n "
732+ "{}\n "
733+ " distance {} intra-area 21 inter-area 22 external 23\n " .format (
734+ router_block , cli_proto
735+ )
736+ )
737+ running = r1 .vtysh_cmd ("show running-config {}" .format (daemon ))
738+ assert (
739+ "distance {} intra-area 21" .format (cli_proto ) in running
740+ ), "expected 'distance {} intra-area 21' in {} running-config, got:\n {}" .format (
741+ cli_proto , daemon , running
742+ )
743+ assert "inter-area 22" in running , running
744+ assert "external 23" in running , running
745+
746+ r1 .vtysh_cmd (
747+ "configure terminal\n "
748+ "{}\n "
749+ " no distance {}\n " .format (router_block , cli_proto )
750+ )
751+ running = r1 .vtysh_cmd ("show running-config {}" .format (daemon ))
752+ assert "intra-area 21" not in running , running
753+ assert "inter-area 22" not in running , running
754+ assert "external 23" not in running , running
755+
756+
694757def test_ospf_area_cli_routes_through_yang ():
695758 """The legacy `area X stub`, `area X stub no-summary`, `area X
696759 default-cost N`, and their `no` forms continue to work via vtysh but
@@ -1021,12 +1084,13 @@ def test_ospf_per_iface_cli_routes_through_yang():
10211084 Drives `ip ospf cost N`, `ip ospf hello-interval N`, `ip ospf
10221085 dead-interval N`, `ip ospf priority N`, `ip ospf mtu-ignore`,
10231086 `ip ospf passive`, `ip ospf retransmit-interval N`, `ip ospf
1024- transmit-delay N` and their v3 siblings via vtysh on r1-eth1
1025- (which the fixture already attached to area 0 for both
1026- daemons), confirms each lands in running-config, then unwinds
1027- via the corresponding `no` form. Covers both the conversion
1028- of the main DEFUN to DEFPY_YANG and the routing through the
1029- NB callbacks landed in the per-interface slices.
1087+ transmit-delay N`, `ip ospf network point-to-point` and their
1088+ v3 siblings via vtysh on r1-eth1 (which the fixture already
1089+ attached to area 0 for both daemons), confirms each lands in
1090+ running-config, then unwinds via the corresponding `no` form.
1091+ Covers both the conversion of the main DEFUN to DEFPY_YANG and
1092+ the routing through the NB callbacks landed in the per-interface
1093+ slices.
10301094 """
10311095 tgen = get_topogen ()
10321096 if tgen .routers_have_failure ():
@@ -1046,6 +1110,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
10461110 " ip ospf passive\n "
10471111 " ip ospf retransmit-interval 23\n "
10481112 " ip ospf transmit-delay 31\n "
1113+ " ip ospf network point-to-point\n "
10491114 )
10501115 running = r1 .vtysh_cmd ("show running-config ospfd" )
10511116 for expected in (
@@ -1057,6 +1122,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
10571122 "ip ospf passive" ,
10581123 "ip ospf retransmit-interval 23" ,
10591124 "ip ospf transmit-delay 31" ,
1125+ "ip ospf network point-to-point" ,
10601126 ):
10611127 assert (
10621128 expected in running
@@ -1075,6 +1141,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
10751141 " no ip ospf passive\n "
10761142 " no ip ospf retransmit-interval\n "
10771143 " no ip ospf transmit-delay\n "
1144+ " no ip ospf network\n "
10781145 )
10791146 running = r1 .vtysh_cmd ("show running-config ospfd" )
10801147 for unexpected in (
@@ -1086,6 +1153,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
10861153 "ip ospf passive" ,
10871154 "ip ospf retransmit-interval 23" ,
10881155 "ip ospf transmit-delay 31" ,
1156+ "ip ospf network point-to-point" ,
10891157 ):
10901158 assert (
10911159 unexpected not in running
@@ -1103,6 +1171,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
11031171 " ipv6 ospf6 passive\n "
11041172 " ipv6 ospf6 retransmit-interval 23\n "
11051173 " ipv6 ospf6 transmit-delay 31\n "
1174+ " ipv6 ospf6 network point-to-point\n "
11061175 )
11071176 running = r1 .vtysh_cmd ("show running-config ospf6d" )
11081177 for expected in (
@@ -1114,6 +1183,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
11141183 "ipv6 ospf6 passive" ,
11151184 "ipv6 ospf6 retransmit-interval 23" ,
11161185 "ipv6 ospf6 transmit-delay 31" ,
1186+ "ipv6 ospf6 network point-to-point" ,
11171187 ):
11181188 assert (
11191189 expected in running
@@ -1132,6 +1202,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
11321202 " no ipv6 ospf6 passive\n "
11331203 " no ipv6 ospf6 retransmit-interval\n "
11341204 " no ipv6 ospf6 transmit-delay\n "
1205+ " no ipv6 ospf6 network\n "
11351206 )
11361207 running = r1 .vtysh_cmd ("show running-config ospf6d" )
11371208 for unexpected in (
@@ -1143,6 +1214,7 @@ def test_ospf_per_iface_cli_routes_through_yang():
11431214 "ipv6 ospf6 passive" ,
11441215 "ipv6 ospf6 retransmit-interval 23" ,
11451216 "ipv6 ospf6 transmit-delay 31" ,
1217+ "ipv6 ospf6 network point-to-point" ,
11461218 ):
11471219 assert (
11481220 unexpected not in running
@@ -1158,6 +1230,44 @@ def test_ospf_per_iface_cli_routes_through_yang():
11581230 )
11591231
11601232
1233+ def test_ospf_network_dmvpn_falls_back_to_legacy ():
1234+ """`ip ospf network point-to-point dmvpn` keeps working via the
1235+ legacy direct-mutation path because RFC 9129's interface-type
1236+ enum doesn't model the FRR-specific dmvpn flag.
1237+
1238+ The DEFPY_YANG body classifies the FRR-modifier as out-of-scope
1239+ for YANG and falls through to ospf_network_legacy_apply. This
1240+ test confirms the running-config still shows the dmvpn modifier
1241+ after the conversion.
1242+ """
1243+ tgen = get_topogen ()
1244+ if tgen .routers_have_failure ():
1245+ pytest .skip ("skipped because of router(s) failure" )
1246+
1247+ r1 = tgen .gears ["r1" ]
1248+
1249+ r1 .vtysh_cmd (
1250+ "configure terminal\n "
1251+ "interface r1-eth1\n "
1252+ " ip ospf network point-to-point dmvpn\n "
1253+ )
1254+ running = r1 .vtysh_cmd ("show running-config ospfd" )
1255+ assert "ip ospf network point-to-point dmvpn" in running , (
1256+ "expected 'ip ospf network point-to-point dmvpn' in running-config "
1257+ "after legacy CLI set, got:\n " + running
1258+ )
1259+
1260+ r1 .vtysh_cmd (
1261+ "configure terminal\n "
1262+ "interface r1-eth1\n "
1263+ " no ip ospf network\n "
1264+ )
1265+ running = r1 .vtysh_cmd ("show running-config ospfd" )
1266+ assert "ip ospf network" not in running , (
1267+ "ip ospf network should be removed after CLI no form, got:\n " + running
1268+ )
1269+
1270+
11611271def test_ospf_yang_preference_config ():
11621272 """per-instance preference (admin distance) round-trip via mgmtd.
11631273
0 commit comments