diff --git a/src/confd/src/ietf-interfaces.c b/src/confd/src/ietf-interfaces.c index 378d8962..6b17ec71 100644 --- a/src/confd/src/ietf-interfaces.c +++ b/src/confd/src/ietf-interfaces.c @@ -653,191 +653,74 @@ skip_mtu: return err; } -static int netdag_write_ethtool(struct dagger *net, const char *ifname, - const char *fmt, ...) +static int netdag_gen_ethtool_autoneg(struct dagger *net, struct lyd_node *cif) { - va_list ap; + struct lyd_node *eth = lydx_get_child(cif, "ethernet"); + struct lyd_node *aneg = lydx_get_child(eth, "auto-negotiation"); + const char *ifname = lydx_get_cattr(cif, "name"); + const char *speed, *duplex; + int mbps, err = 0; FILE *fp; - fp = dagger_fopen_next(net, "init", ifname, 65, "ethtool.sh"); + fp = dagger_fopen_next(net, "init", ifname, 10, "ethtool-aneg.sh"); if (!fp) return -EIO; - va_start(ap, fmt); - vfprintf(fp, fmt, ap); - va_end(ap); + fprintf(fp, "ethtool --change %s autoneg ", ifname); + if (!aneg || lydx_is_enabled(aneg, "enable")) { + fputs("on\n", fp); + } else { + speed = lydx_get_cattr(eth, "speed"); + if (!speed) { + sr_session_set_error_message(net->session, "%s: " + "\"speed\" must be specified " + "when auto-negotiation is disabled", ifname); + err = -EINVAL; + goto out; + } + + mbps = (int)(atof(speed) * 1000.); + if (!((mbps == 10) || (mbps == 100))) { + sr_session_set_error_message(net->session, "%s: " + "\"speed\" must be either 0.01 or 0.1 " + "when auto-negotiation is disabled", ifname); + err = -EINVAL; + goto out; + } + + duplex = lydx_get_cattr(eth, "duplex"); + if (!duplex || (strcmp(duplex, "full") && strcmp(duplex, "half"))) { + sr_session_set_error_message(net->session, "%s: " + "\"duplex\" must be either " + "\"full\" or \"half\" " + "when auto-negotiation is disabled", ifname); + err = -EINVAL; + goto out; + } + + fprintf(fp,"off speed %d duplex %s\n", mbps, duplex); + } +out: fclose(fp); + return err; - return 0; -} - -static const char *lyd_get_autoneg(struct lyd_node *cif) -{ - struct lydx_diff nd; - struct lyd_node *node; - - node = lydx_get_descendant(lyd_child(cif), "ethernet", "auto-negotiation", "enable", NULL); - if (node && lydx_get_diff(node, &nd) && nd.new) - return (strcmp(nd.val, "true") == 0) ? "on" : "off"; - - return NULL; -} - -static const char *lyd_get_duplex(struct lyd_node *cif) -{ - struct lydx_diff nd; - struct lyd_node *node; - - node = lydx_get_descendant(lyd_child(cif), "ethernet", "duplex", NULL); - if (node && lydx_get_diff(node, &nd) && nd.new) - return nd.val; - - return NULL; -} - -static int lyd_get_speed(struct lyd_node *cif) -{ - struct lydx_diff nd; - struct lyd_node *n; - - n = lydx_get_descendant(lyd_child(cif), "ethernet", "speed", NULL); - if (n && lydx_get_diff(n, &nd) && nd.new) - return (int)(atof(nd.val) * 1000); - - return 0; -} - -static int lyd_speed_has_changed(struct lyd_node *dif) -{ - struct lydx_diff nd; - struct lyd_node *n; - - n = lydx_get_descendant(lyd_child(dif), "ethernet", "speed", NULL); - return (n && lydx_get_diff(n, &nd)); -} - -static int lyd_duplex_has_changed(struct lyd_node *dif) -{ - struct lydx_diff nd; - struct lyd_node *n; - - n = lydx_get_descendant(lyd_child(dif), "ethernet", "duplex", NULL); - return (n && lydx_get_diff(n, &nd)); -} - -static int lyd_autoneg_has_changed(struct lyd_node *dif) -{ - struct lydx_diff nd; - struct lyd_node *n; - - n = lydx_get_descendant(lyd_child(dif), "ethernet", "auto-negotiation", "enable", NULL); - return (n && lydx_get_diff(n, &nd)); -} - -static int lyd_autoneg_is_on(struct lyd_node *cif) -{ - const char *val; - - val = lyd_get_autoneg(cif); - if (!val) { - /* TODO Change this to error when auto-neg is true in factory config */ - return 1; - } - return (strcmp(val, "on") == 0); -} - -static int netdag_set_autoneg_off(struct dagger *net, const char *ifname, - const char *duplex, int speed) -{ - if (!speed || !duplex) { - sr_session_set_error_message(net->session, - "Autoneg off requires explicit speed and duplex"); - return SR_ERR_INVAL_ARG; - } - - return netdag_write_ethtool(net, ifname, - "ethtool -s %s autoneg off duplex %s speed %d\n", - ifname, duplex, speed); -} - -static int netdag_set_autoneg_on(struct dagger *net, const char *ifname) -{ - return netdag_write_ethtool(net, ifname, "ethtool -s %s autoneg on\n", ifname); -} - -static int netdag_set_autoneg(struct dagger *net, const char *ifname, struct lyd_node *cif) -{ - const char *autoneg = lyd_get_autoneg(cif); - const char *duplex = lyd_get_duplex(cif); - int speed = lyd_get_speed(cif); - - if (!autoneg) - return SR_ERR_INVAL_ARG; - - if (strcmp(autoneg, "off") == 0) - return netdag_set_autoneg_off(net, ifname, duplex, speed); - - return netdag_set_autoneg_on(net, ifname); -} - -static int netdag_set_speed(struct dagger *net, const char *ifname, struct lyd_node *cif) -{ - int speed = lyd_get_speed(cif); - - if (!speed && !lyd_autoneg_is_on(cif)) { - sr_session_set_error_message(net->session, - "Can't remove speed when autoneg is disabled"); - return SR_ERR_INVAL_ARG; - } - - return netdag_write_ethtool(net, ifname, "ethtool -s %s speed %d\n", - ifname, speed); -} - -static int netdag_set_duplex(struct dagger *net, const char *ifname, struct lyd_node *cif) -{ - const char *duplex = lyd_get_duplex(cif); - - /** - * Duplex has a default value, no need to check if autoneg is off and - * the duplex is removed, which would be a problem otherwise. - */ - - return netdag_write_ethtool(net, ifname, "ethtool -s %s duplex %s\n", - ifname, duplex); } static int netdag_gen_ethtool(struct dagger *net, struct lyd_node *cif, struct lyd_node *dif) { - const char *ifname = lydx_get_cattr(cif, "name"); + struct lyd_node *eth = lydx_get_child(dif, "ethernet"); int err; - if (!strcmp(ifname, "lo")) - return SR_ERR_OK; - - /** - * Autoneg on means duplex and speed doesn't matter. - * Autoneg off requires and set both speed and duplex. - * - * Either way, if autoneg has changed duplex and speed are handled. - */ - if (lyd_autoneg_has_changed(dif)) - return netdag_set_autoneg(net, ifname, cif); - - if (lyd_duplex_has_changed(dif)) { - err = netdag_set_duplex(net, ifname, cif); + if (lydx_get_descendant(lyd_child(eth), "auto-negotiation", "enable", NULL) || + lydx_get_child(eth, "speed") || + lydx_get_child(eth, "duplex")) { + err = netdag_gen_ethtool_autoneg(net, cif); if (err) return err; } - if (lyd_speed_has_changed(dif)) { - err = netdag_set_speed(net, ifname, cif); - if (err) - return err; - } - - return SR_ERR_OK; + return 0; } static int bridge_diff_vlan_port(struct dagger *net, FILE *br, const char *brname, int vid,