uboot/cmd/ethsw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright 2015 Freescale Semiconductor, Inc.
   4 *
   5 * Ethernet Switch commands
   6 */
   7
   8#include <common.h>
   9#include <command.h>
  10#include <env.h>
  11#include <errno.h>
  12#include <env_flags.h>
  13#include <ethsw.h>
  14#include <net.h>
  15
  16static const char *ethsw_name;
  17
  18#define ETHSW_PORT_STATS_HELP "ethsw [port <port_no>] statistics " \
  19"{ [help] | [clear] } - show an l2 switch port's statistics"
  20
  21static int ethsw_port_stats_help_key_func(struct ethsw_command_def *parsed_cmd)
  22{
  23        printf(ETHSW_PORT_STATS_HELP"\n");
  24
  25        return CMD_RET_SUCCESS;
  26}
  27
  28#define ETHSW_LEARN_HELP "ethsw [port <port_no>] learning " \
  29"{ [help] | show | auto | disable } " \
  30"- enable/disable/show learning configuration on a port"
  31
  32static int ethsw_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
  33{
  34        printf(ETHSW_LEARN_HELP"\n");
  35
  36        return CMD_RET_SUCCESS;
  37}
  38
  39#define ETHSW_FDB_HELP "ethsw [port <port_no>] [vlan <vid>] fdb " \
  40"{ [help] | show | flush | { add | del } <mac> } " \
  41"- Add/delete a mac entry in FDB; use show to see FDB entries; " \
  42"if vlan <vid> is missing, VID 1 will be used"
  43
  44static int ethsw_fdb_help_key_func(struct ethsw_command_def *parsed_cmd)
  45{
  46        printf(ETHSW_FDB_HELP"\n");
  47
  48        return CMD_RET_SUCCESS;
  49}
  50
  51#define ETHSW_PVID_HELP "ethsw [port <port_no>] " \
  52"pvid { [help] | show | <pvid> } " \
  53"- set/show PVID (ingress and egress VLAN tagging) for a port"
  54
  55static int ethsw_pvid_help_key_func(struct ethsw_command_def *parsed_cmd)
  56{
  57        printf(ETHSW_PVID_HELP"\n");
  58
  59        return CMD_RET_SUCCESS;
  60}
  61
  62#define ETHSW_VLAN_HELP "ethsw [port <port_no>] vlan " \
  63"{ [help] | show | add <vid> | del <vid> } " \
  64"- add a VLAN to a port (VLAN members)"
  65
  66static int ethsw_vlan_help_key_func(struct ethsw_command_def *parsed_cmd)
  67{
  68        printf(ETHSW_VLAN_HELP"\n");
  69
  70        return CMD_RET_SUCCESS;
  71}
  72
  73#define ETHSW_PORT_UNTAG_HELP "ethsw [port <port_no>] untagged " \
  74"{ [help] | show | all | none | pvid } " \
  75" - set egress tagging mode for a port"
  76
  77static int ethsw_port_untag_help_key_func(struct ethsw_command_def *parsed_cmd)
  78{
  79        printf(ETHSW_PORT_UNTAG_HELP"\n");
  80
  81        return CMD_RET_SUCCESS;
  82}
  83
  84#define ETHSW_EGR_VLAN_TAG_HELP "ethsw [port <port_no>] egress tag " \
  85"{ [help] | show | pvid | classified } " \
  86"- Configure VID source for egress tag. " \
  87"Tag's VID could be the frame's classified VID or the PVID of the port"
  88
  89static int ethsw_egr_tag_help_key_func(struct ethsw_command_def *parsed_cmd)
  90{
  91        printf(ETHSW_EGR_VLAN_TAG_HELP"\n");
  92
  93        return CMD_RET_SUCCESS;
  94}
  95
  96#define ETHSW_VLAN_FDB_HELP "ethsw vlan fdb " \
  97"{ [help] | show | shared | private } " \
  98"- make VLAN learning shared or private"
  99
 100static int ethsw_vlan_learn_help_key_func(struct ethsw_command_def *parsed_cmd)
 101{
 102        printf(ETHSW_VLAN_FDB_HELP"\n");
 103
 104        return CMD_RET_SUCCESS;
 105}
 106
 107#define ETHSW_PORT_INGR_FLTR_HELP "ethsw [port <port_no>] ingress filtering" \
 108" { [help] | show | enable | disable } " \
 109"- enable/disable VLAN ingress filtering on port"
 110
 111static int ethsw_ingr_fltr_help_key_func(struct ethsw_command_def *parsed_cmd)
 112{
 113        printf(ETHSW_PORT_INGR_FLTR_HELP"\n");
 114
 115        return CMD_RET_SUCCESS;
 116}
 117
 118#define ETHSW_PORT_AGGR_HELP "ethsw [port <port_no>] aggr" \
 119" { [help] | show | <lag_group_no> } " \
 120"- get/set LAG group for a port"
 121
 122static int ethsw_port_aggr_help_key_func(struct ethsw_command_def *parsed_cmd)
 123{
 124        printf(ETHSW_PORT_AGGR_HELP"\n");
 125
 126        return CMD_RET_SUCCESS;
 127}
 128
 129static struct keywords_to_function {
 130        enum ethsw_keyword_id cmd_keyword[ETHSW_MAX_CMD_PARAMS];
 131        int cmd_func_offset;
 132        int (*keyword_function)(struct ethsw_command_def *parsed_cmd);
 133} ethsw_cmd_def[] = {
 134                {
 135                        .cmd_keyword = {
 136                                        ethsw_id_enable,
 137                                        ethsw_id_key_end,
 138                        },
 139                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 140                                                    port_enable),
 141                        .keyword_function = NULL,
 142                }, {
 143                        .cmd_keyword = {
 144                                        ethsw_id_disable,
 145                                        ethsw_id_key_end,
 146                        },
 147                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 148                                                    port_disable),
 149                        .keyword_function = NULL,
 150                }, {
 151                        .cmd_keyword = {
 152                                        ethsw_id_show,
 153                                        ethsw_id_key_end,
 154                        },
 155                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 156                                                    port_show),
 157                        .keyword_function = NULL,
 158                }, {
 159                        .cmd_keyword = {
 160                                        ethsw_id_statistics,
 161                                        ethsw_id_help,
 162                                        ethsw_id_key_end,
 163                        },
 164                        .cmd_func_offset = -1,
 165                        .keyword_function = &ethsw_port_stats_help_key_func,
 166                }, {
 167                        .cmd_keyword = {
 168                                        ethsw_id_statistics,
 169                                        ethsw_id_key_end,
 170                        },
 171                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 172                                                    port_stats),
 173                        .keyword_function = NULL,
 174                }, {
 175                        .cmd_keyword = {
 176                                        ethsw_id_statistics,
 177                                        ethsw_id_clear,
 178                                        ethsw_id_key_end,
 179                        },
 180                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 181                                                    port_stats_clear),
 182                        .keyword_function = NULL,
 183                }, {
 184                        .cmd_keyword = {
 185                                        ethsw_id_learning,
 186                                        ethsw_id_key_end,
 187                        },
 188                        .cmd_func_offset = -1,
 189                        .keyword_function = &ethsw_learn_help_key_func,
 190                }, {
 191                        .cmd_keyword = {
 192                                        ethsw_id_learning,
 193                                        ethsw_id_help,
 194                                        ethsw_id_key_end,
 195                        },
 196                        .cmd_func_offset = -1,
 197                        .keyword_function = &ethsw_learn_help_key_func,
 198                }, {
 199                        .cmd_keyword = {
 200                                        ethsw_id_learning,
 201                                        ethsw_id_show,
 202                                        ethsw_id_key_end,
 203                        },
 204                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 205                                                    port_learn_show),
 206                        .keyword_function = NULL,
 207                }, {
 208                        .cmd_keyword = {
 209                                        ethsw_id_learning,
 210                                        ethsw_id_auto,
 211                                        ethsw_id_key_end,
 212                        },
 213                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 214                                                    port_learn),
 215                        .keyword_function = NULL,
 216                }, {
 217                        .cmd_keyword = {
 218                                        ethsw_id_learning,
 219                                        ethsw_id_disable,
 220                                        ethsw_id_key_end,
 221                        },
 222                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 223                                                    port_learn),
 224                        .keyword_function = NULL,
 225                }, {
 226                        .cmd_keyword = {
 227                                        ethsw_id_fdb,
 228                                        ethsw_id_key_end,
 229                        },
 230                        .cmd_func_offset = -1,
 231                        .keyword_function = &ethsw_fdb_help_key_func,
 232                }, {
 233                        .cmd_keyword = {
 234                                        ethsw_id_fdb,
 235                                        ethsw_id_help,
 236                                        ethsw_id_key_end,
 237                        },
 238                        .cmd_func_offset = -1,
 239                        .keyword_function = &ethsw_fdb_help_key_func,
 240                }, {
 241                        .cmd_keyword = {
 242                                        ethsw_id_fdb,
 243                                        ethsw_id_show,
 244                                        ethsw_id_key_end,
 245                        },
 246                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 247                                                    fdb_show),
 248                        .keyword_function = NULL,
 249                }, {
 250                        .cmd_keyword = {
 251                                        ethsw_id_fdb,
 252                                        ethsw_id_flush,
 253                                        ethsw_id_key_end,
 254                        },
 255                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 256                                                    fdb_flush),
 257                        .keyword_function = NULL,
 258                }, {
 259                        .cmd_keyword = {
 260                                        ethsw_id_fdb,
 261                                        ethsw_id_add,
 262                                        ethsw_id_add_del_mac,
 263                                        ethsw_id_key_end,
 264                        },
 265                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 266                                                    fdb_entry_add),
 267                        .keyword_function = NULL,
 268                }, {
 269                        .cmd_keyword = {
 270                                        ethsw_id_fdb,
 271                                        ethsw_id_del,
 272                                        ethsw_id_add_del_mac,
 273                                        ethsw_id_key_end,
 274                        },
 275                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 276                                                    fdb_entry_del),
 277                        .keyword_function = NULL,
 278                }, {
 279                        .cmd_keyword = {
 280                                        ethsw_id_pvid,
 281                                        ethsw_id_key_end,
 282                        },
 283                        .cmd_func_offset = -1,
 284                        .keyword_function = &ethsw_pvid_help_key_func,
 285                }, {
 286                        .cmd_keyword = {
 287                                        ethsw_id_pvid,
 288                                        ethsw_id_help,
 289                                        ethsw_id_key_end,
 290                        },
 291                        .cmd_func_offset = -1,
 292                        .keyword_function = &ethsw_pvid_help_key_func,
 293                }, {
 294                        .cmd_keyword = {
 295                                        ethsw_id_pvid,
 296                                        ethsw_id_show,
 297                                        ethsw_id_key_end,
 298                        },
 299                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 300                                                    pvid_show),
 301                        .keyword_function = NULL,
 302                }, {
 303                        .cmd_keyword = {
 304                                        ethsw_id_pvid,
 305                                        ethsw_id_pvid_no,
 306                                        ethsw_id_key_end,
 307                        },
 308                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 309                                                    pvid_set),
 310                        .keyword_function = NULL,
 311                }, {
 312                        .cmd_keyword = {
 313                                        ethsw_id_vlan,
 314                                        ethsw_id_key_end,
 315                        },
 316                        .cmd_func_offset = -1,
 317                        .keyword_function = &ethsw_vlan_help_key_func,
 318                }, {
 319                        .cmd_keyword = {
 320                                        ethsw_id_vlan,
 321                                        ethsw_id_help,
 322                                        ethsw_id_key_end,
 323                        },
 324                        .cmd_func_offset = -1,
 325                        .keyword_function = &ethsw_vlan_help_key_func,
 326                }, {
 327                        .cmd_keyword = {
 328                                        ethsw_id_vlan,
 329                                        ethsw_id_show,
 330                                        ethsw_id_key_end,
 331                        },
 332                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 333                                                    vlan_show),
 334                        .keyword_function = NULL,
 335                }, {
 336                        .cmd_keyword = {
 337                                        ethsw_id_vlan,
 338                                        ethsw_id_add,
 339                                        ethsw_id_add_del_no,
 340                                        ethsw_id_key_end,
 341                        },
 342                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 343                                                    vlan_set),
 344                        .keyword_function = NULL,
 345                }, {
 346                        .cmd_keyword = {
 347                                        ethsw_id_vlan,
 348                                        ethsw_id_del,
 349                                        ethsw_id_add_del_no,
 350                                        ethsw_id_key_end,
 351                        },
 352                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 353                                                    vlan_set),
 354                        .keyword_function = NULL,
 355                }, {
 356                        .cmd_keyword = {
 357                                        ethsw_id_untagged,
 358                                        ethsw_id_key_end,
 359                        },
 360                        .cmd_func_offset = -1,
 361                        .keyword_function = &ethsw_port_untag_help_key_func,
 362                }, {
 363                        .cmd_keyword = {
 364                                        ethsw_id_untagged,
 365                                        ethsw_id_help,
 366                                        ethsw_id_key_end,
 367                        },
 368                        .cmd_func_offset = -1,
 369                        .keyword_function = &ethsw_port_untag_help_key_func,
 370                }, {
 371                        .cmd_keyword = {
 372                                        ethsw_id_untagged,
 373                                        ethsw_id_show,
 374                                        ethsw_id_key_end,
 375                        },
 376                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 377                                                    port_untag_show),
 378                        .keyword_function = NULL,
 379                }, {
 380                        .cmd_keyword = {
 381                                        ethsw_id_untagged,
 382                                        ethsw_id_all,
 383                                        ethsw_id_key_end,
 384                        },
 385                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 386                                                    port_untag_set),
 387                        .keyword_function = NULL,
 388                }, {
 389                        .cmd_keyword = {
 390                                        ethsw_id_untagged,
 391                                        ethsw_id_none,
 392                                        ethsw_id_key_end,
 393                        },
 394                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 395                                                    port_untag_set),
 396                        .keyword_function = NULL,
 397                }, {
 398                        .cmd_keyword = {
 399                                        ethsw_id_untagged,
 400                                        ethsw_id_pvid,
 401                                        ethsw_id_key_end,
 402                        },
 403                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 404                                                    port_untag_set),
 405                        .keyword_function = NULL,
 406                }, {
 407                        .cmd_keyword = {
 408                                        ethsw_id_egress,
 409                                        ethsw_id_tag,
 410                                        ethsw_id_key_end,
 411                        },
 412                        .cmd_func_offset = -1,
 413                        .keyword_function = &ethsw_egr_tag_help_key_func,
 414                }, {
 415                        .cmd_keyword = {
 416                                        ethsw_id_egress,
 417                                        ethsw_id_tag,
 418                                        ethsw_id_help,
 419                                        ethsw_id_key_end,
 420                        },
 421                        .cmd_func_offset = -1,
 422                        .keyword_function = &ethsw_egr_tag_help_key_func,
 423                }, {
 424                        .cmd_keyword = {
 425                                        ethsw_id_egress,
 426                                        ethsw_id_tag,
 427                                        ethsw_id_show,
 428                                        ethsw_id_key_end,
 429                        },
 430                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 431                                                    port_egr_vlan_show),
 432                        .keyword_function = NULL,
 433                }, {
 434                        .cmd_keyword = {
 435                                        ethsw_id_egress,
 436                                        ethsw_id_tag,
 437                                        ethsw_id_pvid,
 438                                        ethsw_id_key_end,
 439                        },
 440                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 441                                                    port_egr_vlan_set),
 442                        .keyword_function = NULL,
 443                }, {
 444                        .cmd_keyword = {
 445                                        ethsw_id_egress,
 446                                        ethsw_id_tag,
 447                                        ethsw_id_classified,
 448                                        ethsw_id_key_end,
 449                        },
 450                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 451                                                    port_egr_vlan_set),
 452                        .keyword_function = NULL,
 453                }, {
 454                        .cmd_keyword = {
 455                                        ethsw_id_vlan,
 456                                        ethsw_id_fdb,
 457                                        ethsw_id_key_end,
 458                        },
 459                        .cmd_func_offset = -1,
 460                        .keyword_function = &ethsw_vlan_learn_help_key_func,
 461                }, {
 462                        .cmd_keyword = {
 463                                        ethsw_id_vlan,
 464                                        ethsw_id_fdb,
 465                                        ethsw_id_help,
 466                                        ethsw_id_key_end,
 467                        },
 468                        .cmd_func_offset = -1,
 469                        .keyword_function = &ethsw_vlan_learn_help_key_func,
 470                }, {
 471                        .cmd_keyword = {
 472                                        ethsw_id_vlan,
 473                                        ethsw_id_fdb,
 474                                        ethsw_id_show,
 475                                        ethsw_id_key_end,
 476                        },
 477                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 478                                                    vlan_learn_show),
 479                        .keyword_function = NULL,
 480                }, {
 481                        .cmd_keyword = {
 482                                        ethsw_id_vlan,
 483                                        ethsw_id_fdb,
 484                                        ethsw_id_shared,
 485                                        ethsw_id_key_end,
 486                        },
 487                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 488                                                    vlan_learn_set),
 489                        .keyword_function = NULL,
 490                }, {
 491                        .cmd_keyword = {
 492                                        ethsw_id_vlan,
 493                                        ethsw_id_fdb,
 494                                        ethsw_id_private,
 495                                        ethsw_id_key_end,
 496                        },
 497                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 498                                                    vlan_learn_set),
 499                        .keyword_function = NULL,
 500                }, {
 501                        .cmd_keyword = {
 502                                        ethsw_id_ingress,
 503                                        ethsw_id_filtering,
 504                                        ethsw_id_key_end,
 505                        },
 506                        .cmd_func_offset = -1,
 507                        .keyword_function = &ethsw_ingr_fltr_help_key_func,
 508                }, {
 509                        .cmd_keyword = {
 510                                        ethsw_id_ingress,
 511                                        ethsw_id_filtering,
 512                                        ethsw_id_help,
 513                                        ethsw_id_key_end,
 514                        },
 515                        .cmd_func_offset = -1,
 516                        .keyword_function = &ethsw_ingr_fltr_help_key_func,
 517                }, {
 518                        .cmd_keyword = {
 519                                        ethsw_id_ingress,
 520                                        ethsw_id_filtering,
 521                                        ethsw_id_show,
 522                                        ethsw_id_key_end,
 523                        },
 524                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 525                                                    port_ingr_filt_show),
 526                        .keyword_function = NULL,
 527                }, {
 528                        .cmd_keyword = {
 529                                        ethsw_id_ingress,
 530                                        ethsw_id_filtering,
 531                                        ethsw_id_enable,
 532                                        ethsw_id_key_end,
 533                        },
 534                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 535                                                    port_ingr_filt_set),
 536                        .keyword_function = NULL,
 537                }, {
 538                        .cmd_keyword = {
 539                                        ethsw_id_ingress,
 540                                        ethsw_id_filtering,
 541                                        ethsw_id_disable,
 542                                        ethsw_id_key_end,
 543                        },
 544                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 545                                                    port_ingr_filt_set),
 546                        .keyword_function = NULL,
 547                }, {
 548                        .cmd_keyword = {
 549                                        ethsw_id_aggr,
 550                                        ethsw_id_key_end,
 551                        },
 552                        .cmd_func_offset = -1,
 553                        .keyword_function = &ethsw_port_aggr_help_key_func,
 554                }, {
 555                        .cmd_keyword = {
 556                                        ethsw_id_aggr,
 557                                        ethsw_id_help,
 558                                        ethsw_id_key_end,
 559                        },
 560                        .cmd_func_offset = -1,
 561                        .keyword_function = &ethsw_port_aggr_help_key_func,
 562                }, {
 563                        .cmd_keyword = {
 564                                        ethsw_id_aggr,
 565                                        ethsw_id_show,
 566                                        ethsw_id_key_end,
 567                        },
 568                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 569                                                    port_aggr_show),
 570                        .keyword_function = NULL,
 571                }, {
 572                        .cmd_keyword = {
 573                                        ethsw_id_aggr,
 574                                        ethsw_id_aggr_no,
 575                                        ethsw_id_key_end,
 576                        },
 577                        .cmd_func_offset = offsetof(struct ethsw_command_func,
 578                                                    port_aggr_set),
 579                        .keyword_function = NULL,
 580                },
 581};
 582
 583struct keywords_optional {
 584        int cmd_keyword[ETHSW_MAX_CMD_PARAMS];
 585} cmd_opt_def[] = {
 586                {
 587                                .cmd_keyword = {
 588                                                ethsw_id_port,
 589                                                ethsw_id_port_no,
 590                                                ethsw_id_key_end,
 591                                },
 592                }, {
 593                                .cmd_keyword = {
 594                                                ethsw_id_vlan,
 595                                                ethsw_id_vlan_no,
 596                                                ethsw_id_key_end,
 597                                },
 598                }, {
 599                                .cmd_keyword = {
 600                                                ethsw_id_port,
 601                                                ethsw_id_port_no,
 602                                                ethsw_id_vlan,
 603                                                ethsw_id_vlan_no,
 604                                                ethsw_id_key_end,
 605                                },
 606                },
 607};
 608
 609static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc, char
 610                             *const argv[], int *argc_nr,
 611                             struct ethsw_command_def *parsed_cmd);
 612static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
 613                              char *const argv[], int *argc_nr,
 614                              struct ethsw_command_def *parsed_cmd);
 615static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
 616                              char *const argv[], int *argc_nr,
 617                              struct ethsw_command_def *parsed_cmd);
 618static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
 619                              char *const argv[], int *argc_nr,
 620                              struct ethsw_command_def *parsed_cmd);
 621static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
 622                                  char *const argv[], int *argc_nr,
 623                                  struct ethsw_command_def *parsed_cmd);
 624static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
 625                              char *const argv[], int *argc_nr,
 626                              struct ethsw_command_def *parsed_cmd);
 627
 628/*
 629 * Define properties for each keyword;
 630 * keep the order synced with enum ethsw_keyword_id
 631 */
 632struct keyword_def {
 633        const char *keyword_name;
 634        int (*match)(enum ethsw_keyword_id key_id, int argc, char *const argv[],
 635                     int *argc_nr, struct ethsw_command_def *parsed_cmd);
 636} keyword[] = {
 637                {
 638                                .keyword_name = "help",
 639                                .match = &keyword_match_gen,
 640                }, {
 641                                .keyword_name = "show",
 642                                .match = &keyword_match_gen,
 643                }, {
 644                                .keyword_name = "port",
 645                                .match = &keyword_match_port
 646                },  {
 647                                .keyword_name = "enable",
 648                                .match = &keyword_match_gen,
 649                }, {
 650                                .keyword_name = "disable",
 651                                .match = &keyword_match_gen,
 652                }, {
 653                                .keyword_name = "statistics",
 654                                .match = &keyword_match_gen,
 655                }, {
 656                                .keyword_name = "clear",
 657                                .match = &keyword_match_gen,
 658                }, {
 659                                .keyword_name = "learning",
 660                                .match = &keyword_match_gen,
 661                }, {
 662                                .keyword_name = "auto",
 663                                .match = &keyword_match_gen,
 664                }, {
 665                                .keyword_name = "vlan",
 666                                .match = &keyword_match_vlan,
 667                }, {
 668                                .keyword_name = "fdb",
 669                                .match = &keyword_match_gen,
 670                }, {
 671                                .keyword_name = "add",
 672                                .match = &keyword_match_mac_addr,
 673                }, {
 674                                .keyword_name = "del",
 675                                .match = &keyword_match_mac_addr,
 676                }, {
 677                                .keyword_name = "flush",
 678                                .match = &keyword_match_gen,
 679                }, {
 680                                .keyword_name = "pvid",
 681                                .match = &keyword_match_pvid,
 682                }, {
 683                                .keyword_name = "untagged",
 684                                .match = &keyword_match_gen,
 685                }, {
 686                                .keyword_name = "all",
 687                                .match = &keyword_match_gen,
 688                }, {
 689                                .keyword_name = "none",
 690                                .match = &keyword_match_gen,
 691                }, {
 692                                .keyword_name = "egress",
 693                                .match = &keyword_match_gen,
 694                }, {
 695                                .keyword_name = "tag",
 696                                .match = &keyword_match_gen,
 697                }, {
 698                                .keyword_name = "classified",
 699                                .match = &keyword_match_gen,
 700                }, {
 701                                .keyword_name = "shared",
 702                                .match = &keyword_match_gen,
 703                }, {
 704                                .keyword_name = "private",
 705                                .match = &keyword_match_gen,
 706                }, {
 707                                .keyword_name = "ingress",
 708                                .match = &keyword_match_gen,
 709                }, {
 710                                .keyword_name = "filtering",
 711                                .match = &keyword_match_gen,
 712                }, {
 713                                .keyword_name = "aggr",
 714                                .match = &keyword_match_aggr,
 715                },
 716};
 717
 718/*
 719 * Function used by an Ethernet Switch driver to set the functions
 720 * that must be called by the parser when an ethsw command is given
 721 */
 722int ethsw_define_functions(const struct ethsw_command_func *cmd_func)
 723{
 724        int i;
 725        void **aux_p;
 726        int (*cmd_func_aux)(struct ethsw_command_def *);
 727
 728        if (!cmd_func->ethsw_name)
 729                return -EINVAL;
 730
 731        ethsw_name = cmd_func->ethsw_name;
 732
 733        for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
 734                /*
 735                 * get the pointer to the function send by the Ethernet Switch
 736                 * driver that corresponds to the proper ethsw command
 737                 */
 738                if (ethsw_cmd_def[i].keyword_function)
 739                        continue;
 740
 741                aux_p = (void *)cmd_func + ethsw_cmd_def[i].cmd_func_offset;
 742
 743                cmd_func_aux = (int (*)(struct ethsw_command_def *)) *aux_p;
 744                ethsw_cmd_def[i].keyword_function = cmd_func_aux;
 745        }
 746
 747        return 0;
 748}
 749
 750/* Generic function used to match a keyword only by a string */
 751static int keyword_match_gen(enum ethsw_keyword_id key_id, int argc,
 752                             char *const argv[], int *argc_nr,
 753                             struct ethsw_command_def *parsed_cmd)
 754{
 755        if (strcmp(argv[*argc_nr], keyword[key_id].keyword_name) == 0) {
 756                parsed_cmd->cmd_to_keywords[*argc_nr] = key_id;
 757
 758                return 1;
 759        }
 760        return 0;
 761}
 762
 763/* Function used to match the command's port */
 764static int keyword_match_port(enum ethsw_keyword_id key_id, int argc,
 765                              char *const argv[], int *argc_nr,
 766                              struct ethsw_command_def *parsed_cmd)
 767{
 768        unsigned long val;
 769
 770        if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
 771                return 0;
 772
 773        if (*argc_nr + 1 >= argc)
 774                return 0;
 775
 776        if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
 777                parsed_cmd->port = val;
 778                (*argc_nr)++;
 779                parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_port_no;
 780                return 1;
 781        }
 782
 783        return 0;
 784}
 785
 786/* Function used to match the command's vlan */
 787static int keyword_match_vlan(enum ethsw_keyword_id key_id, int argc,
 788                              char *const argv[], int *argc_nr,
 789                              struct ethsw_command_def *parsed_cmd)
 790{
 791        unsigned long val;
 792        int aux;
 793
 794        if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
 795                return 0;
 796
 797        if (*argc_nr + 1 >= argc)
 798                return 0;
 799
 800        if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
 801                parsed_cmd->vid = val;
 802                (*argc_nr)++;
 803                parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_vlan_no;
 804                return 1;
 805        }
 806
 807        aux = *argc_nr + 1;
 808
 809        if (keyword_match_gen(ethsw_id_add, argc, argv, &aux, parsed_cmd))
 810                parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add;
 811        else if (keyword_match_gen(ethsw_id_del, argc, argv, &aux, parsed_cmd))
 812                parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_del;
 813        else
 814                return 0;
 815
 816        if (*argc_nr + 2 >= argc)
 817                return 0;
 818
 819        if (strict_strtoul(argv[*argc_nr + 2], 10, &val) != -EINVAL) {
 820                parsed_cmd->vid = val;
 821                (*argc_nr) += 2;
 822                parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_add_del_no;
 823                return 1;
 824        }
 825
 826        return 0;
 827}
 828
 829/* Function used to match the command's pvid */
 830static int keyword_match_pvid(enum ethsw_keyword_id key_id, int argc,
 831                              char *const argv[], int *argc_nr,
 832                              struct ethsw_command_def *parsed_cmd)
 833{
 834        unsigned long val;
 835
 836        if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
 837                return 0;
 838
 839        if (*argc_nr + 1 >= argc)
 840                return 1;
 841
 842        if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
 843                parsed_cmd->vid = val;
 844                (*argc_nr)++;
 845                parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_pvid_no;
 846        }
 847
 848        return 1;
 849}
 850
 851/* Function used to match the command's MAC address */
 852static int keyword_match_mac_addr(enum ethsw_keyword_id key_id, int argc,
 853                                     char *const argv[], int *argc_nr,
 854                                     struct ethsw_command_def *parsed_cmd)
 855{
 856        if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
 857                return 0;
 858
 859        if ((*argc_nr + 1 >= argc) ||
 860            !is_broadcast_ethaddr(parsed_cmd->ethaddr))
 861                return 1;
 862
 863        if (eth_validate_ethaddr_str(argv[*argc_nr + 1])) {
 864                printf("Invalid MAC address: %s\n", argv[*argc_nr + 1]);
 865                return 0;
 866        }
 867
 868        string_to_enetaddr(argv[*argc_nr + 1], parsed_cmd->ethaddr);
 869
 870        if (is_broadcast_ethaddr(parsed_cmd->ethaddr)) {
 871                memset(parsed_cmd->ethaddr, 0xFF, sizeof(parsed_cmd->ethaddr));
 872                return 0;
 873        }
 874
 875        parsed_cmd->cmd_to_keywords[*argc_nr + 1] = ethsw_id_add_del_mac;
 876
 877        return 1;
 878}
 879
 880/* Function used to match the command's aggregation number */
 881static int keyword_match_aggr(enum ethsw_keyword_id key_id, int argc,
 882                              char *const argv[], int *argc_nr,
 883                              struct ethsw_command_def *parsed_cmd)
 884{
 885        unsigned long val;
 886
 887        if (!keyword_match_gen(key_id, argc, argv, argc_nr, parsed_cmd))
 888                return 0;
 889
 890        if (*argc_nr + 1 >= argc)
 891                return 1;
 892
 893        if (strict_strtoul(argv[*argc_nr + 1], 10, &val) != -EINVAL) {
 894                parsed_cmd->aggr_grp = val;
 895                (*argc_nr)++;
 896                parsed_cmd->cmd_to_keywords[*argc_nr] = ethsw_id_aggr_no;
 897        }
 898
 899        return 1;
 900}
 901
 902/* Finds optional keywords and modifies *argc_va to skip them */
 903static void cmd_keywords_opt_check(const struct ethsw_command_def *parsed_cmd,
 904                                   int *argc_val)
 905{
 906        int i;
 907        int keyw_opt_matched;
 908        int argc_val_max;
 909        int const *cmd_keyw_p;
 910        int const *cmd_keyw_opt_p;
 911
 912        /* remember the best match */
 913        argc_val_max = *argc_val;
 914
 915        /*
 916         * check if our command's optional keywords match the optional
 917         * keywords of an available command
 918         */
 919        for (i = 0; i < ARRAY_SIZE(cmd_opt_def); i++) {
 920                keyw_opt_matched = 0;
 921                cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_opt_matched];
 922                cmd_keyw_opt_p = &cmd_opt_def[i].cmd_keyword[keyw_opt_matched];
 923
 924                /*
 925                 * increase the number of keywords that
 926                 * matched with a command
 927                 */
 928                while (keyw_opt_matched + *argc_val <
 929                       parsed_cmd->cmd_keywords_nr &&
 930                       *cmd_keyw_opt_p != ethsw_id_key_end &&
 931                       *(cmd_keyw_p + *argc_val) == *cmd_keyw_opt_p) {
 932                        keyw_opt_matched++;
 933                        cmd_keyw_p++;
 934                        cmd_keyw_opt_p++;
 935                }
 936
 937                /*
 938                 * if all our optional command's keywords perfectly match an
 939                 * optional pattern, then we can move to the next defined
 940                 * keywords in our command; remember the one that matched the
 941                 * greatest number of keywords
 942                 */
 943                if (keyw_opt_matched + *argc_val <=
 944                    parsed_cmd->cmd_keywords_nr &&
 945                    *cmd_keyw_opt_p == ethsw_id_key_end &&
 946                    *argc_val + keyw_opt_matched > argc_val_max)
 947                        argc_val_max = *argc_val + keyw_opt_matched;
 948        }
 949
 950        *argc_val = argc_val_max;
 951}
 952
 953/*
 954 * Finds the function to call based on keywords and
 955 * modifies *argc_va to skip them
 956 */
 957static void cmd_keywords_check(struct ethsw_command_def *parsed_cmd,
 958                               int *argc_val)
 959{
 960        int i;
 961        int keyw_matched;
 962        int *cmd_keyw_p;
 963        int *cmd_keyw_def_p;
 964
 965        /*
 966         * check if our command's keywords match the
 967         * keywords of an available command
 968         */
 969        for (i = 0; i < ARRAY_SIZE(ethsw_cmd_def); i++) {
 970                keyw_matched = 0;
 971                cmd_keyw_p = &parsed_cmd->cmd_to_keywords[keyw_matched];
 972                cmd_keyw_def_p = &ethsw_cmd_def[i].cmd_keyword[keyw_matched];
 973
 974                /*
 975                 * increase the number of keywords that
 976                 * matched with a command
 977                 */
 978                while (keyw_matched + *argc_val < parsed_cmd->cmd_keywords_nr &&
 979                       *cmd_keyw_def_p != ethsw_id_key_end &&
 980                       *(cmd_keyw_p + *argc_val) == *cmd_keyw_def_p) {
 981                        keyw_matched++;
 982                        cmd_keyw_p++;
 983                        cmd_keyw_def_p++;
 984                }
 985
 986                /*
 987                 * if all our command's keywords perfectly match an
 988                 * available command, then we get the function we need to call
 989                 * to configure the Ethernet Switch
 990                 */
 991                if (keyw_matched && keyw_matched + *argc_val ==
 992                    parsed_cmd->cmd_keywords_nr &&
 993                    *cmd_keyw_def_p == ethsw_id_key_end) {
 994                        *argc_val += keyw_matched;
 995                        parsed_cmd->cmd_function =
 996                                        ethsw_cmd_def[i].keyword_function;
 997                        return;
 998                }
 999        }
1000}
1001
1002/* find all the keywords in the command */
1003static int keywords_find(int argc, char *const argv[],
1004                         struct ethsw_command_def *parsed_cmd)
1005{
1006        int i;
1007        int j;
1008        int argc_val;
1009        int rc = CMD_RET_SUCCESS;
1010
1011        for (i = 1; i < argc; i++) {
1012                for (j = 0; j < ethsw_id_count; j++) {
1013                        if (keyword[j].match(j, argc, argv, &i, parsed_cmd))
1014                                break;
1015                }
1016        }
1017
1018        /* if there is no keyword match for a word, the command is invalid */
1019        for (i = 1; i < argc; i++)
1020                if (parsed_cmd->cmd_to_keywords[i] == ethsw_id_key_end)
1021                        rc = CMD_RET_USAGE;
1022
1023        parsed_cmd->cmd_keywords_nr = argc;
1024        argc_val = 1;
1025
1026        /* get optional parameters first */
1027        cmd_keywords_opt_check(parsed_cmd, &argc_val);
1028
1029        if (argc_val == parsed_cmd->cmd_keywords_nr)
1030                return CMD_RET_USAGE;
1031
1032        /*
1033         * check the keywords and if a match is found,
1034         * get the function to call
1035         */
1036        cmd_keywords_check(parsed_cmd, &argc_val);
1037
1038        /* error if not all commands' parameters were matched */
1039        if (argc_val == parsed_cmd->cmd_keywords_nr) {
1040                if (!parsed_cmd->cmd_function) {
1041                        printf("Command not available for: %s\n", ethsw_name);
1042                        rc = CMD_RET_FAILURE;
1043                }
1044        } else {
1045                rc = CMD_RET_USAGE;
1046        }
1047
1048        return rc;
1049}
1050
1051static void command_def_init(struct ethsw_command_def *parsed_cmd)
1052{
1053        int i;
1054
1055        for (i = 0; i < ETHSW_MAX_CMD_PARAMS; i++)
1056                parsed_cmd->cmd_to_keywords[i] = ethsw_id_key_end;
1057
1058        parsed_cmd->port = ETHSW_CMD_PORT_ALL;
1059        parsed_cmd->vid = ETHSW_CMD_VLAN_ALL;
1060        parsed_cmd->aggr_grp = ETHSW_CMD_AGGR_GRP_NONE;
1061        parsed_cmd->cmd_function = NULL;
1062
1063        /* We initialize the MAC address with the Broadcast address */
1064        memset(parsed_cmd->ethaddr, 0xff, sizeof(parsed_cmd->ethaddr));
1065}
1066
1067/* function to interpret commands starting with "ethsw " */
1068static int do_ethsw(struct cmd_tbl *cmdtp, int flag, int argc,
1069                    char *const argv[])
1070{
1071        struct ethsw_command_def parsed_cmd;
1072        int rc = CMD_RET_SUCCESS;
1073
1074        if (argc == 1 || argc >= ETHSW_MAX_CMD_PARAMS)
1075                return CMD_RET_USAGE;
1076
1077        command_def_init(&parsed_cmd);
1078
1079        rc = keywords_find(argc, argv, &parsed_cmd);
1080
1081        if (rc == CMD_RET_SUCCESS)
1082                rc = parsed_cmd.cmd_function(&parsed_cmd);
1083
1084        return rc;
1085}
1086
1087#define ETHSW_PORT_CONF_HELP "[port <port_no>] { enable | disable | show } " \
1088"- enable/disable a port; show a port's configuration"
1089
1090U_BOOT_CMD(ethsw, ETHSW_MAX_CMD_PARAMS, 0, do_ethsw,
1091           "Ethernet l2 switch commands",
1092           ETHSW_PORT_CONF_HELP"\n"
1093           ETHSW_PORT_STATS_HELP"\n"
1094           ETHSW_LEARN_HELP"\n"
1095           ETHSW_FDB_HELP"\n"
1096           ETHSW_PVID_HELP"\n"
1097           ETHSW_VLAN_HELP"\n"
1098           ETHSW_PORT_UNTAG_HELP"\n"
1099           ETHSW_EGR_VLAN_TAG_HELP"\n"
1100           ETHSW_VLAN_FDB_HELP"\n"
1101           ETHSW_PORT_INGR_FLTR_HELP"\n"
1102           ETHSW_PORT_AGGR_HELP"\n"
1103);
1104