netmod-wg / yang-next

Feature requests for future versions of YANG
6 stars 0 forks source link

Injection of circular imports by deviation #126

Open janlindblad opened 6 months ago

janlindblad commented 6 months ago

RFC 7950 is unclear on whether import dependencies may be introduced by way of deviations.

According to RFC 7950:

   There MUST NOT be any circular chains of imports.  For example, if
   module "a" imports module "b", "b" cannot import "a".

This is clear and I believe most people find this reasonable enough.

With this rule in mind, I can make two modules a and b, where a imports b. Module b does not and cannot import a.

module a {
  yang-version 1.1;
  namespace "http://example.com/ns/a";
  prefix a;

  import b {
    prefix b;
  }

  typedef A {
    type uint32;
  }

  leaf aa {
    type A;
  }
  leaf ab {
    type b:B;
  }
}

module b {
  yang-version 1.1;
  namespace "http://example.com/ns/b";
  prefix b;

  typedef B {
    type uint32;
  }

  leaf bb {
    type B;
  }
}

Now let's add a deviation in a separate module d. The deviation module can import both a and b (since neither a or b imports d), and it changes the structure so that module b now refers to a type in module a.

module d {
  yang-version 1.1;
  namespace "http://example.com/ns/d";
  prefix d;

  import a {
    prefix a;
  }
  import b {
    prefix b;
  }

  deviation /b:bb {
    deviate replace {
      type a:A;
    }
  }
}

As far as I can tell, this follows all the explicit YANG rules regarding deviations and imports. Still, it would not have been possible to create this YANG structure without a deviation. Module b cannot refer to types or objects in module a without an outside intervention.

Is the construct in module d legal? RFC 7950 is not very clear on the subject, but it does say:

   After applying all deviations announced by a server, in any order,
   the resulting data model MUST still be valid.

If "applying" means actually replacing the original module text with the deviated text, then I'm fairly sure module d would violate the rule against circular imports. If "applying" is something that happens on a more "global" or "logical" level, then maybe this should be allowed?

By allowing deviations of this kind, we might create a temptation for people to use deviations for their own modules in order to create YANG structures otherwise not possible. I find this problematic, since I don't like deviations much. On the other hand, allowing deviations of this kind increases the freedom of expression in the YANG world. I think many would regard a moratorium as another YANG CLR (crappy little rule).

If we were to decide that this sort of deviation is allowed, wouldn't a logical conclusion be that we should drop the circular imports rule? Compilers could very well track which modules have already been imported (like in python), and not go into unbounded spin just because there is a circular reference loop.

As a side note, recent versions of the OpenConfig model have fallen into this YANG-module reference trap. Some OC modules violate RFC 7950 rules because their authors were not able to plan ahead and divide their modules properly into layers. They have skipped importing modules that they are using because their compiler errors out if they do the import, but the compiler they use misses/tolerates the illegal reference without the needed import. If modules could mutually import each other, this problem would be easily solved.

Several major vendors of YANG-based servers have navigated around this problem by essentially using a single module (namespace) for most of their functionality. Then there are no restrictions for what part of the model can reference what else, but everything ends up in a single (rather huge) namespace.

abierman commented 1 week ago

IMO the cited text is not being violated. It does not consider this deviation corner-case.

I had to fix this cornercase in our server because this happens with some real modules. IMO this is an implementation detail. The YANG spec could mention this issue in the deviations section.

Another issue: what if the deviation replaces the type with one from a module that is not even imported into the deviated module. It is only imported into the module with the deviation-stmt.

Need text clarification.

Must Do