mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-04 06:43:00 +02:00
confd: add support for veth pairs, incl. new native YANG models
This change adds support for Linux veth pairs and is also a bit of a cleanup of our native yang models, more on that below. The interesting things are the use of submodule(s) for veth, and the addition of the deviation for the deprecated /if:interfaces-state. Unfortunately the `fprintf(ip, "link add dev %s down", ifname);` had to be delagated from netdag_gen_afspec_add() because of this change. This because we only know very late that the peer-end of the pair should be skipped. Having a lingering `ip link add dev foo down` causes iproute2 to fail hard. A note about Yang models. According to RFC they must follow the naming standard; 'org-name' and use prefixes 'org-shortname'. So we've decided to standardize on 'infix-modulename' and 'infix-mn', where 'modulename' is the standard model we extend, and 'mn' is the prefix used by that standard model. For example - infix-interfaces extend ietf-interfaces and use infix-if - infix-if-veth is a submodule extending infix with veth pairs Upcoming bridge and lag models follow the same pattern. The use of submodules require a patch to sysrepo, included earlier, and allows us to have the same 'infix-if:', or 'infix-interfaecs:' prefix to all ietf-interfaces extensions. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
committed by
Tobias Waldekranz
parent
7c17793e5a
commit
1b7d72a07c
@@ -23,6 +23,8 @@
|
||||
#define DEBUG_IFACE(_iface, _fmt, ...) \
|
||||
DEBUG("%s: " _fmt, lydx_get_cattr(_iface, "name"), ##__VA_ARGS__)
|
||||
|
||||
#define IF_XPATH "/ietf-interfaces:interfaces/interface"
|
||||
|
||||
static const char *iffeat[] = {
|
||||
"if-mib",
|
||||
NULL
|
||||
@@ -41,6 +43,8 @@ static const struct srx_module_requirement ietf_if_reqs[] = {
|
||||
{ .dir = YANG_PATH_, .name = "ietf-if-vlan-encapsulation", .rev = "2023-01-26" },
|
||||
{ .dir = YANG_PATH_, .name = "ietf-ip", .rev = "2018-02-22" },
|
||||
{ .dir = YANG_PATH_, .name = "infix-ip", .rev = "2023-04-24" },
|
||||
{ .dir = YANG_PATH_, .name = "infix-if-type", .rev = "2023-06-09" },
|
||||
{ .dir = YANG_PATH_, .name = "infix-interfaces", .rev = "2023-06-05" },
|
||||
|
||||
{ NULL }
|
||||
};
|
||||
@@ -100,6 +104,58 @@ static char *iface_xpath(const char *xpath)
|
||||
return path;
|
||||
}
|
||||
|
||||
static int ifchange_cand_infer_veth(sr_session_ctx_t *session, const char *path)
|
||||
{
|
||||
char *ifname, *type, *peer, *xpath, *val;
|
||||
sr_error_t err = SR_ERR_OK;
|
||||
size_t cnt = 0;
|
||||
|
||||
xpath = iface_xpath(path);
|
||||
if (!xpath)
|
||||
return SR_ERR_SYS;
|
||||
|
||||
type = srx_get_str(session, "%s/type", xpath);
|
||||
if (!type || strcmp(type, "infix-if-type:veth"))
|
||||
goto out;
|
||||
|
||||
ifname = srx_get_str(session, "%s/name", xpath);
|
||||
if (!ifname)
|
||||
goto out_free_type;
|
||||
|
||||
peer = srx_get_str(session, "%s/veth/peer", xpath);
|
||||
if (!peer) {
|
||||
ERROR("INFER VETH name %s no peer", ifname);
|
||||
goto out_free_ifname;
|
||||
}
|
||||
|
||||
err = srx_nitems(session, &cnt, "/interfaces/interface[name='%s']/name", peer);
|
||||
if (err || cnt) {
|
||||
ERROR("%s nitems: %zu, err %d", peer, cnt, err);
|
||||
goto out_free_peer;
|
||||
}
|
||||
|
||||
val = "infix-if-type:veth";
|
||||
err = srx_set_str(session, val, 0, IF_XPATH "[name='%s']/type", peer);
|
||||
if (err) {
|
||||
ERROR("failed setting iface %s type %s, err %d", peer, val, err);
|
||||
goto out_free_peer;
|
||||
}
|
||||
|
||||
err = srx_set_str(session, ifname, 0, IF_XPATH "[name='%s']/infix-interfaces:veth/peer", peer);
|
||||
if (err)
|
||||
ERROR("failed setting iface %s peer %s, err %d", peer, ifname, err);
|
||||
|
||||
out_free_peer:
|
||||
free(peer);
|
||||
out_free_ifname:
|
||||
free(ifname);
|
||||
out_free_type:
|
||||
free(type);
|
||||
out:
|
||||
free(xpath);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ifchange_cand_infer_vlan(sr_session_ctx_t *session, const char *path)
|
||||
{
|
||||
sr_val_t inferred = { .type = SR_STRING_T };
|
||||
@@ -217,6 +273,8 @@ static int ifchange_cand_infer_type(sr_session_ctx_t *session, const char *path)
|
||||
inferred.data.string_val = "iana-if-type:bridge";
|
||||
else if (!fnmatch("lag+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "iana-if-type:ieee8023adLag";
|
||||
else if (!fnmatch("veth+([0-9a-z_-])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "infix-if-type:veth";
|
||||
else if (!fnmatch("vlan+([0-9])", ifname, FNM_EXTMATCH))
|
||||
inferred.data.string_val = "iana-if-type:l2vlan";
|
||||
else if (!fnmatch("*.+([0-9])", ifname, FNM_EXTMATCH))
|
||||
@@ -265,6 +323,10 @@ static int ifchange_cand(sr_session_ctx_t *session, uint32_t sub_id, const char
|
||||
if (err)
|
||||
break;
|
||||
|
||||
err = ifchange_cand_infer_veth(session, new->xpath);
|
||||
if (err)
|
||||
break;
|
||||
|
||||
err = ifchange_cand_infer_vlan(session, new->xpath);
|
||||
if (err)
|
||||
break;
|
||||
@@ -505,10 +567,39 @@ static int netdag_gen_sysctl(struct dagger *net,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int netdag_gen_veth(struct dagger *net, struct lyd_node *dif,
|
||||
struct lyd_node *cif, FILE *ip)
|
||||
{
|
||||
const char *ifname = lydx_get_cattr(cif, "name");
|
||||
struct lyd_node *node;
|
||||
const char *peer;
|
||||
int err;
|
||||
|
||||
node = lydx_get_descendant(lyd_child(cif), "veth", NULL);
|
||||
if (!node)
|
||||
return -EINVAL;
|
||||
|
||||
peer = lydx_get_cattr(node, "peer");
|
||||
if (dagger_should_skip(net, ifname)) {
|
||||
ERROR("%s already exists, skipping", ifname);
|
||||
err = dagger_add_dep(net, ifname, peer);
|
||||
if (err)
|
||||
return ERR_IFACE(cif, err, "Unable to add dep \"%s\" to %s",
|
||||
peer, ifname);
|
||||
} else {
|
||||
ERROR("Creating veth %s peer %s", ifname, peer);
|
||||
dagger_skip_iface(net, peer);
|
||||
fprintf(ip, "link add dev %s down type veth peer %s\n", ifname, peer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
|
||||
struct lyd_node *cif, FILE *ip)
|
||||
{
|
||||
const char *parent, *ifname = lydx_get_cattr(cif, "name");
|
||||
const char *parent = lydx_get_cattr(cif, "parent-interface");
|
||||
const char *ifname = lydx_get_cattr(cif, "name");
|
||||
struct lydx_diff typed, vidd;
|
||||
struct lyd_node *otag;
|
||||
const char *proto;
|
||||
@@ -516,9 +607,6 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
|
||||
|
||||
DEBUG("");
|
||||
|
||||
parent = lydx_get_cattr(cif, "parent-interface");
|
||||
fprintf(ip, " link %s", parent);
|
||||
|
||||
err = dagger_add_dep(net, ifname, parent);
|
||||
if (err)
|
||||
return ERR_IFACE(cif, err, "Unable to add dep \"%s\"", parent);
|
||||
@@ -528,10 +616,12 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
|
||||
"dot1q-vlan",
|
||||
"outer-tag",
|
||||
NULL);
|
||||
if (!otag)
|
||||
if (!otag) {
|
||||
ERROR("missing mandatory outer-tag");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(ip, " type vlan");
|
||||
fprintf(ip, "link add dev %s down link %s type vlan", ifname, parent);
|
||||
|
||||
if (lydx_get_diff(lydx_get_child(otag, "tag-type"), &typed)) {
|
||||
if (!strcmp(typed.new, "ieee802-dot1q-types:c-vlan"))
|
||||
@@ -548,6 +638,7 @@ static int netdag_gen_vlan(struct dagger *net, struct lyd_node *dif,
|
||||
if (lydx_get_diff(lydx_get_child(otag, "vlan-id"), &vidd))
|
||||
fprintf(ip, " id %s", vidd.new);
|
||||
|
||||
fputc('\n', ip);
|
||||
DEBUG("");
|
||||
return 0;
|
||||
}
|
||||
@@ -561,9 +652,11 @@ static int netdag_gen_afspec_add(struct dagger *net, struct lyd_node *dif,
|
||||
|
||||
DEBUG_IFACE(dif, "");
|
||||
|
||||
fprintf(ip, "link add dev %s down", ifname);
|
||||
|
||||
if (!strcmp(iftype, "iana-if-type:l2vlan")) {
|
||||
if (!strcmp(iftype, "iana-if-type:bridge")) {
|
||||
fprintf(ip, "link add dev %s type bridge\n", ifname);
|
||||
} else if (!strcmp(iftype, "infix-if-type:veth")) {
|
||||
err = netdag_gen_veth(net, NULL, cif, ip);
|
||||
} else if (!strcmp(iftype, "iana-if-type:l2vlan")) {
|
||||
err = netdag_gen_vlan(net, NULL, cif, ip);
|
||||
} else {
|
||||
ERROR("Unable to add unsupported interface type \"%s\"",
|
||||
@@ -574,7 +667,6 @@ static int netdag_gen_afspec_add(struct dagger *net, struct lyd_node *dif,
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
fputc('\n', ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -587,6 +679,8 @@ static int netdag_gen_afspec_set(struct dagger *net, struct lyd_node *dif,
|
||||
|
||||
if (!strcmp(iftype, "iana-if-type:l2vlan"))
|
||||
return netdag_gen_vlan(net, dif, cif, ip);
|
||||
if (!strcmp(iftype, "infix-if-type:veth"))
|
||||
return 0;
|
||||
|
||||
ERROR("Unable to configure unsupported interface type \"%s\"", iftype);
|
||||
return -ENOSYS;
|
||||
@@ -603,6 +697,8 @@ static bool netdag_must_del(struct lyd_node *dif, struct lyd_node *cif)
|
||||
"dot1q-vlan",
|
||||
"outer-tag",
|
||||
NULL);
|
||||
if (!strcmp(iftype, "infix-if-type:veth"))
|
||||
return lydx_get_descendant(lyd_child(dif), "peer", NULL);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
module infix-if-type {
|
||||
yang-version 1.1;
|
||||
namespace "urn:infix:types:ns:yang:1.0";
|
||||
prefix infixift;
|
||||
|
||||
import iana-if-type {
|
||||
prefix ianaift;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Infix extensions to IANA interfaces types";
|
||||
|
||||
revision 2023-06-09 {
|
||||
description "Initial revision.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
/*
|
||||
* Identities
|
||||
*/
|
||||
|
||||
identity veth {
|
||||
base ianaift:ilan;
|
||||
description "Linux virtual Ethernet pair.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
submodule infix-if-veth {
|
||||
yang-version 1.1;
|
||||
belongs-to infix-interfaces {
|
||||
prefix infix-if;
|
||||
}
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
import infix-if-type {
|
||||
prefix infixift;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Linux virtual Ethernet pair extension for ietf-interfaces.";
|
||||
|
||||
revision 2023-06-05 {
|
||||
description "Initial revision.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
when "derived-from-or-self(if:type, 'infixift:veth')" {
|
||||
description "Only shown for if:type infixift:veth (ianaift:ilan)";
|
||||
}
|
||||
|
||||
description "Augments the interface model with virtual Ethernet pairs.";
|
||||
|
||||
container veth {
|
||||
description "Virtual Ethernet (veth) pair.";
|
||||
|
||||
leaf peer {
|
||||
type if:interface-ref;
|
||||
must '(deref(.)/../if:type = "infixift:veth") and
|
||||
deref(deref(.)/../veth/peer) = ../../if:name' {
|
||||
error-message "Must refer to the peer interface (other end of othe pair).";
|
||||
}
|
||||
mandatory true;
|
||||
description "Peer veth interface to which this interface is connected.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
module infix-interfaces {
|
||||
yang-version 1.1;
|
||||
namespace "urn:infix:interfaces:ns:yang:1.0";
|
||||
prefix infix-if;
|
||||
|
||||
include infix-if-veth;
|
||||
|
||||
import ietf-interfaces {
|
||||
prefix if;
|
||||
}
|
||||
|
||||
organization "KernelKit";
|
||||
contact "kernelkit@googlegroups.com";
|
||||
description "Linux bridge and lag extensions for ietf-interfaces.";
|
||||
|
||||
revision 2023-06-05 {
|
||||
description "Initial revision.";
|
||||
reference "internal";
|
||||
}
|
||||
|
||||
/*
|
||||
* Data Nodes
|
||||
*/
|
||||
|
||||
augment "/if:interfaces/if:interface" {
|
||||
description "Augments the interface model with mutually exclusive guards.";
|
||||
|
||||
choice port {
|
||||
description "An interface can only be member of either a bridge or a link aggregate.";
|
||||
}
|
||||
}
|
||||
|
||||
deviation "/if:interfaces-state" {
|
||||
deviate not-supported;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user