-
Notifications
You must be signed in to change notification settings - Fork 23
Srv6 l2 dx2 #466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Srv6 l2 dx2 #466
Changes from all commits
a05bd26
15e1942
f3e226e
5ab4d9c
9f9c684
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -266,6 +266,9 @@ static int grout_gr_nexthop_to_frr_nexthop( | |
| case SR_BEHAVIOR_END_DT46: | ||
| action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46; | ||
| break; | ||
| case SR_BEHAVIOR_END_DX2: | ||
| action = ZEBRA_SEG6_LOCAL_ACTION_END_DX2; | ||
| break; | ||
| } | ||
|
|
||
| ctx.table = ifindex_grout_to_frr(sr6->out_vrf_id); | ||
|
|
@@ -726,6 +729,11 @@ grout_add_nexthop(uint32_t nh_id, gr_nh_origin_t origin, const struct nexthop *n | |
| nh->nh_srv6->seg6local_ctx.table | ||
| ); | ||
| break; | ||
| case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: | ||
| sr6_local->behavior = SR_BEHAVIOR_END_DX2; | ||
| // FIXME | ||
| sr6_local->out_vrf_id = ifindex_frr_to_grout(GR_VRF_ID_ALL); | ||
| break; | ||
|
Comment on lines
+732
to
+736
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: Incorrect function usage for DX2 interface mapping. The code passes For END.DX2 behavior, you need to extract the output interface from the seg6local context (similar to how other behaviors use Expected pattern based on other behaviorsOther local behaviors extract the interface/table from the nexthop context: case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
sr6_local->behavior = SR_BEHAVIOR_END_DT6;
sr6_local->out_vrf_id = ifindex_frr_to_grout(
nh->nh_srv6->seg6local_ctx.table
);
break;For DX2, you should extract the output interface from the appropriate field in 🤖 Prompt for AI Agents |
||
| default: | ||
| gr_log_err( | ||
| "not supported srv6 local behaviour action=%u", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -51,6 +51,7 @@ typedef enum : uint16_t { | |
| typedef enum : uint8_t { | ||
| GR_IFACE_MODE_L3 = 0, | ||
| GR_IFACE_MODE_L1_XC, | ||
| GR_IFACE_MODE_SRV6_XC, | ||
| GR_IFACE_MODE_COUNT | ||
| } gr_iface_mode_t; | ||
|
|
||
|
|
@@ -74,6 +75,7 @@ struct __gr_iface_base { | |
| uint16_t vrf_id; // L3 addressing and routing domain | ||
| uint16_t domain_id; // L2 xconnect peer interface id | ||
| }; | ||
| uint32_t mode_data; // Abstract mode data | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels a bit hacky. Could you explain the reasoning behind this opaque parameter?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the type specific info, we need a mode specific info. |
||
| uint32_t speed; // Link speed in Megabit/sec. | ||
| }; | ||
|
|
||
|
|
@@ -452,6 +454,8 @@ static inline const char *gr_iface_mode_name(gr_iface_mode_t mode) { | |
| return "l3"; | ||
| case GR_IFACE_MODE_L1_XC: | ||
| return "l1-xc"; | ||
| case GR_IFACE_MODE_SRV6_XC: | ||
| return "srv6-evpn"; | ||
| case GR_IFACE_MODE_COUNT: | ||
| break; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,11 +18,40 @@ | |
| #include <unistd.h> | ||
|
|
||
| static STAILQ_HEAD(, cli_iface_type) types = STAILQ_HEAD_INITIALIZER(types); | ||
| static STAILQ_HEAD(, cli_iface_mode) modes = STAILQ_HEAD_INITIALIZER(modes); | ||
|
|
||
| void register_iface_type(struct cli_iface_type *type) { | ||
| STAILQ_INSERT_TAIL(&types, type, next); | ||
| } | ||
|
|
||
| void register_iface_mode(struct cli_iface_mode *mode) { | ||
| STAILQ_INSERT_TAIL(&modes, mode, next); | ||
| } | ||
|
|
||
| struct ec_node *with_iface_set_callback(cmd_iface_set_cb_t cb, struct ec_node *node) { | ||
| if (node == NULL) | ||
| return NULL; | ||
| struct ec_dict *attrs = ec_node_attrs(node); | ||
| if (attrs == NULL || ec_dict_set(attrs, CALLBACK_ATTR_IFACE_MODE, cb, NULL) < 0) { | ||
| ec_node_free(node); | ||
| node = NULL; | ||
| } | ||
| return node; | ||
| } | ||
|
|
||
| static cmd_iface_set_cb_t find_cmd_iface_mode_callback(const struct ec_pnode *parsed) { | ||
| const struct ec_pnode *p; | ||
|
|
||
| for (p = parsed; p != NULL; p = EC_PNODE_ITER_NEXT(parsed, p, true)) { | ||
| const struct ec_node *node = ec_pnode_get_node(p); | ||
| cmd_iface_set_cb_t cb = ec_dict_get(ec_node_attrs(node), CALLBACK_ATTR_IFACE_MODE); | ||
| if (cb != NULL) | ||
| return cb; | ||
| } | ||
|
|
||
| return errno_set_null(EOPNOTSUPP); | ||
| } | ||
|
|
||
| const struct cli_iface_type *type_from_name(const char *name) { | ||
| const struct cli_iface_type *type; | ||
|
|
||
|
|
@@ -57,6 +86,7 @@ int complete_iface_types( | |
| } | ||
| return 0; | ||
| } | ||
|
|
||
| const struct cli_iface_type *type_from_id(gr_iface_type_t type_id) { | ||
| const struct cli_iface_type *type; | ||
|
|
||
|
|
@@ -68,6 +98,17 @@ const struct cli_iface_type *type_from_id(gr_iface_type_t type_id) { | |
| return NULL; | ||
| } | ||
|
|
||
| const struct cli_iface_mode *mode_from_id(gr_iface_mode_t mode_id) { | ||
| const struct cli_iface_mode *mode; | ||
|
|
||
| STAILQ_FOREACH (mode, &modes, next) { | ||
| if (mode->mode_id == mode_id) | ||
| return mode; | ||
| } | ||
| errno = ENODEV; | ||
| return NULL; | ||
| } | ||
|
|
||
| int complete_iface_names( | ||
| struct gr_api_client *c, | ||
| const struct ec_node *node, | ||
|
|
@@ -147,6 +188,7 @@ uint64_t parse_iface_args( | |
| size_t info_size, | ||
| bool update | ||
| ) { | ||
| const struct ec_pnode *node; | ||
| const char *name, *promisc; | ||
| uint64_t set_attrs = 0; | ||
|
|
||
|
|
@@ -191,6 +233,19 @@ uint64_t parse_iface_args( | |
| if (arg_u16(p, "VRF", &iface->vrf_id) == 0) | ||
| set_attrs |= GR_IFACE_SET_VRF; | ||
|
|
||
| if ((node = ec_pnode_find(p, "IFACE_MODE")) != NULL) { | ||
| if (ec_pnode_find(node, "l3")) { | ||
| set_attrs |= GR_IFACE_SET_MODE; | ||
| set_attrs |= GR_IFACE_SET_VRF; | ||
| iface->mode = GR_IFACE_MODE_L3; | ||
| iface->vrf_id = 0; | ||
| } else { | ||
| cmd_iface_set_cb_t cb = find_cmd_iface_mode_callback(node); | ||
| if (cb) | ||
| cb(c, iface, node, &set_attrs); | ||
| } | ||
| } | ||
|
Comment on lines
+236
to
+247
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mode configuration failure is silently ignored. Lines 243-245: when This differs from other parse errors in this function, which jump to the 🔧 Propagate the error } else {
cmd_iface_set_cb_t cb = find_cmd_iface_mode_callback(node);
- if (cb)
- cb(c, iface, node, &set_attrs);
+ if (cb == NULL)
+ goto err;
+ cb(c, iface, node, &set_attrs);
}
}🤖 Prompt for AI Agents |
||
|
|
||
| return set_attrs; | ||
| err: | ||
| return 0; | ||
|
|
@@ -232,10 +287,12 @@ static cmd_status_t iface_list(struct gr_api_client *c, const struct ec_pnode *p | |
| scols_table_new_column(table, "DOMAIN", 0, 0); | ||
| scols_table_new_column(table, "TYPE", 0, 0); | ||
| scols_table_new_column(table, "INFO", 0, 0); | ||
| scols_table_new_column(table, "", 0, 0); | ||
| scols_table_set_column_separator(table, " "); | ||
|
|
||
| gr_api_client_stream_foreach (iface, ret, c, GR_INFRA_IFACE_LIST, sizeof(req), &req) { | ||
| const struct cli_iface_type *type = type_from_id(iface->type); | ||
| const struct cli_iface_mode *mode = mode_from_id(iface->mode); | ||
| struct libscols_line *line = scols_table_new_line(table, NULL); | ||
| char buf[128]; | ||
|
|
||
|
|
@@ -253,17 +310,8 @@ static cmd_status_t iface_list(struct gr_api_client *c, const struct ec_pnode *p | |
| scols_line_set_data(line, 2, buf); | ||
|
|
||
| // mode | ||
| switch (iface->mode) { | ||
| case GR_IFACE_MODE_L1_XC: | ||
| scols_line_set_data(line, 3, "XC"); | ||
| break; | ||
| case GR_IFACE_MODE_L3: | ||
| scols_line_set_data(line, 3, "L3"); | ||
| break; | ||
| default: | ||
| scols_line_sprintf(line, 3, "%u", iface->mode); | ||
| break; | ||
| } | ||
| assert(mode != NULL); | ||
| scols_line_sprintf(line, 3, "%s", mode->str); | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // vrf | ||
| scols_line_sprintf(line, 4, "%u", iface->vrf_id); | ||
|
|
@@ -276,6 +324,11 @@ static cmd_status_t iface_list(struct gr_api_client *c, const struct ec_pnode *p | |
| buf[0] = 0; | ||
| type->list_info(c, iface, buf, sizeof(buf)); | ||
| scols_line_set_data(line, 6, buf); | ||
| if (mode->list_info) { | ||
| buf[0] = 0; | ||
| mode->list_info(c, iface, buf, sizeof(buf)); | ||
| scols_line_set_data(line, 7, buf); | ||
| } | ||
christophefontaine marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| scols_print_table(table); | ||
|
|
@@ -436,6 +489,7 @@ static cmd_status_t iface_rates(struct gr_api_client *c, const struct ec_pnode * | |
|
|
||
| static cmd_status_t iface_show(struct gr_api_client *c, const struct ec_pnode *p) { | ||
| const struct cli_iface_type *type; | ||
| const struct cli_iface_mode *mode; | ||
| char buf[128]; | ||
|
|
||
| if (arg_str(p, "stats") != NULL) { | ||
|
|
@@ -473,12 +527,19 @@ static cmd_status_t iface_show(struct gr_api_client *c, const struct ec_pnode *p | |
| assert(type != NULL); | ||
| type->show(c, iface); | ||
|
|
||
| mode = mode_from_id(iface->mode); | ||
| assert(mode); | ||
| if (mode->show) | ||
| mode->show(c, iface); | ||
|
|
||
| free(iface); | ||
|
|
||
| return CMD_SUCCESS; | ||
| } | ||
|
|
||
| static int ctx_init(struct ec_node *root) { | ||
| struct ec_node *iface_mode = NULL; | ||
| struct cli_iface_mode *mode; | ||
| int ret; | ||
|
|
||
| if (INTERFACE_ADD_CTX(root) == NULL) | ||
|
|
@@ -487,6 +548,17 @@ static int ctx_init(struct ec_node *root) { | |
| if (INTERFACE_SET_CTX(root) == NULL) | ||
| return -1; | ||
|
|
||
| // IFACE_MODE is present many times in the ecoli cli tree: | ||
| // It can be configured with "interface add" and "interface set". | ||
| // Also, each interface type (port, vlan, ... ) will need to be attached | ||
| // all interface modes. | ||
| while ((iface_mode = ec_node_find_next(root, iface_mode, "IFACE_MODE"))) { | ||
| STAILQ_FOREACH (mode, &modes, next) { | ||
| if ((ret = mode->init(iface_mode)) < 0) | ||
| return ret; | ||
| } | ||
|
Comment on lines
+555
to
+559
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a comment explaining that there are as many IFACE_MODE nodes as number of interfaces and that we need to call mode->init() on all of them? |
||
| } | ||
|
|
||
| ret = CLI_COMMAND( | ||
| INTERFACE_CTX(root), | ||
| "del NAME", | ||
|
|
@@ -584,7 +656,19 @@ static struct cli_event_printer printer = { | |
| }, | ||
| }; | ||
|
|
||
| static int l3_mode_init(struct ec_node *) { | ||
| // This default l3 mode is handled statically | ||
| return 0; | ||
| } | ||
|
|
||
| static struct cli_iface_mode iface_mode_l3 = { | ||
| .mode_id = GR_IFACE_MODE_L3, | ||
| .str = "L3", | ||
| .init = l3_mode_init, | ||
| }; | ||
|
|
||
| static void __attribute__((constructor, used)) init(void) { | ||
| cli_context_register(&ctx); | ||
| cli_event_printer_register(&printer); | ||
| register_iface_mode(&iface_mode_l3); | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.