From d8494e30d22e22f4ce8490ceed8400eeb18135c9 Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Mon, 2 Oct 2023 16:55:47 +0200 Subject: [PATCH] Add support for setting and fetching IPv4/IPv6 interface MTU Setting the link MTU in Linux changes the sysctl IPV6 MTU, so we have to set the IPv6 MTU on each run in case the IPv4 MTU changes. Hence, this also means the IPv6 MTU must be set *after* the IPv4 (link) MTU. statd has been updated to read the sysctl setting for IPv6 MTU. Notice how the loopback interface is unsupported for config + status. Fixes issue #151 Signed-off-by: Joachim Wiberg --- src/confd/src/ietf-interfaces.c | 65 +++++++++++++++++++------ src/confd/yang/infix-ip@2023-09-14.yang | 8 --- src/statd/iface-ip-addr.c | 21 +++++--- 3 files changed, 66 insertions(+), 28 deletions(-) diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c index 4cd6c1d7..d4727ae5 100644 --- a/src/confd/src/ietf-interfaces.c +++ b/src/confd/src/ietf-interfaces.c @@ -416,6 +416,22 @@ static int netdag_set_conf_addrs(FILE *ip, const char *ifname, return 0; } +static int netdag_gen_link_mtu(FILE *ip, struct lyd_node *dif) +{ + const char *ifname = lydx_get_cattr(dif, "name"); + struct lyd_node *node; + struct lydx_diff nd; + + if (!strcmp(ifname, "lo")) /* skip for now */ + return 0; + + node = lydx_get_descendant(lyd_child(dif), "ipv4", "mtu", NULL); + if (node && lydx_get_diff(node, &nd)) + fprintf(ip, "link set %s mtu %s\n", ifname, nd.new ? nd.val : "1500"); + + return 0; +} + static int netdag_gen_link_addr(FILE *ip, struct lyd_node *cif, struct lyd_node *dif) { const char *ifname = lydx_get_cattr(dif, "name"); @@ -570,12 +586,12 @@ static int netdag_gen_ipv4_autoconf(struct dagger *net, struct lyd_node *cif, return err; } -static int netdag_gen_sysctl_bool(struct dagger *net, - const char *ifname, FILE **fpp, - struct lyd_node *node, - const char *fmt, ...) +static int netdag_gen_sysctl_setting(struct dagger *net, const char *ifname, FILE **fpp, + int isboolean, const char *fallback, + struct lyd_node *node, const char *fmt, ...) { struct lydx_diff nd; + const char *value; va_list ap; if (!node) @@ -584,18 +600,32 @@ static int netdag_gen_sysctl_bool(struct dagger *net, if (!lydx_get_diff(node, &nd)) return 0; - *fpp = *fpp ? : dagger_fopen_next(net, "init", ifname, - 60, "init.sysctl"); + *fpp = *fpp ? : dagger_fopen_next(net, "init", ifname, 60, "init.sysctl"); if (!*fpp) return -EIO; va_start(ap, fmt); vfprintf(*fpp, fmt, ap); va_end(ap); - fprintf(*fpp, " = %u\n", (nd.new && !strcmp(nd.val, "true")) ? 1 : 0); + + if (isboolean) { + if (nd.new && !strcmp(nd.val, "true")) + value = "1"; + else + value = "0"; + } else { + if (nd.new) + value = nd.val; + else + value = fallback; + } + + fprintf(*fpp, " = %s\n", value); + return 0; } static int netdag_gen_sysctl(struct dagger *net, + struct lyd_node *cif, struct lyd_node *dif) { const char *ifname = lydx_get_cattr(dif, "name"); @@ -604,15 +634,21 @@ static int netdag_gen_sysctl(struct dagger *net, int err = 0; node = lydx_get_descendant(lyd_child(dif), "ipv4", "forwarding", NULL); - err = err ? : netdag_gen_sysctl_bool(net, ifname, &sysctl, node, - "net.ipv4.conf.%s.forwarding", - ifname); + err = err ? : netdag_gen_sysctl_setting(net, ifname, &sysctl, 1, "0", node, + "net.ipv4.conf.%s.forwarding", ifname); node = lydx_get_descendant(lyd_child(dif), "ipv6", "forwarding", NULL); - err = err ? : netdag_gen_sysctl_bool(net, ifname, &sysctl, node, - "net.ipv6.conf.%s.forwarding", - ifname); + err = err ? : netdag_gen_sysctl_setting(net, ifname, &sysctl, 1, "0", node, + "net.ipv6.conf.%s.forwarding", ifname); + if (!strcmp(ifname, "lo")) /* skip for now */ + goto skip_mtu; + + node = lydx_get_descendant(lyd_child(cif), "ipv6", "mtu", NULL); + err = err ? : netdag_gen_sysctl_setting(net, ifname, &sysctl, 0, "1280", node, + "net.ipv6.conf.%s.mtu", ifname); + +skip_mtu: if (sysctl) fclose(sysctl); @@ -1093,6 +1129,7 @@ static sr_error_t netdag_gen_iface(struct dagger *net, } /* Set Addresses */ + err = err ? : netdag_gen_link_mtu(ip, dif); err = err ? : netdag_gen_link_addr(ip, cif, dif); err = err ? : netdag_gen_ip_addrs(ip, "ipv4", cif, dif); err = err ? : netdag_gen_ip_addrs(ip, "ipv6", cif, dif); @@ -1104,7 +1141,7 @@ static sr_error_t netdag_gen_iface(struct dagger *net, if (!attr || !strcmp(attr, "true")) fprintf(ip, "link set dev %s up state up\n", ifname); - err = err ? : netdag_gen_sysctl(net, dif); + err = err ? : netdag_gen_sysctl(net, cif, dif); err_close_ip: fclose(ip); diff --git a/src/confd/yang/infix-ip@2023-09-14.yang b/src/confd/yang/infix-ip@2023-09-14.yang index c92e15b5..2cbd816b 100644 --- a/src/confd/yang/infix-ip@2023-09-14.yang +++ b/src/confd/yang/infix-ip@2023-09-14.yang @@ -50,10 +50,6 @@ module infix-ip { } } - deviation "/if:interfaces/if:interface/ip:ipv4/ip:mtu" { - deviate not-supported; - } - deviation "/if:interfaces/if:interface/ip:ipv4/ip:address/ip:subnet/ip:netmask" { deviate not-supported; } @@ -62,10 +58,6 @@ module infix-ip { deviate not-supported; } - deviation "/if:interfaces/if:interface/ip:ipv6/ip:mtu" { - deviate not-supported; - } - deviation "/if:interfaces/if:interface/ip:ipv6/ip:address/ip:status" { deviate not-supported; } diff --git a/src/statd/iface-ip-addr.c b/src/statd/iface-ip-addr.c index 5362f1c4..b47c54eb 100644 --- a/src/statd/iface-ip-addr.c +++ b/src/statd/iface-ip-addr.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -47,6 +48,7 @@ static const char *get_yang_origin(const char *protocol) static int ly_add_ip_mtu(const struct ly_ctx *ctx, struct lyd_node *node, char *xpath, json_t *j_iface, char *ifname) { + json_int_t j_mtu; json_t *j_val; int err; @@ -57,14 +59,21 @@ static int ly_add_ip_mtu(const struct ly_ctx *ctx, struct lyd_node *node, if (strcmp(ifname, "lo") == 0) return SR_ERR_OK; - j_val = json_object_get(j_iface, "mtu"); - if (!json_is_integer(j_val)) { - ERROR("Expected a JSON integer for 'mtu'"); - return SR_ERR_SYS; + if (strstr(xpath, "ipv4")) { + j_val = json_object_get(j_iface, "mtu"); + if (!json_is_integer(j_val)) { + ERROR("Expected a JSON integer for 'mtu'"); + return SR_ERR_SYS; + } + j_mtu = json_integer_value(j_val); + } else { + if (readllf(&j_mtu, "/proc/sys/net/ipv6/conf/%s/mtu", ifname)) { + ERROR("Failed reading sysctl value of %s IPv6 MTU: %s", ifname, strerror(errno)); + return SR_ERR_SYS; + } } - err = lydx_new_path(ctx, &node, xpath, "mtu", "%lld", - json_integer_value(j_val)); + err = lydx_new_path(ctx, &node, xpath, "mtu", "%lld", j_mtu); if (err) { ERROR("Error, adding 'mtu' to data tree, libyang error %d", err); return SR_ERR_LY;