qmp/hmp: add rocker device support
Add QMP/HMP support for rocker devices.  This is mostly for debugging purposes
to see inside the device's tables and port configurations.  Some examples:
(qemu) info rocker sw1
name: sw1
id: 0x0000013512005452
ports: 4
(qemu) info rocker-ports sw1
            ena/    speed/ auto
      port  link    duplex neg?
     sw1.1  up     10G  FD  No
     sw1.2  up     10G  FD  No
     sw1.3  !ena   10G  FD  No
     sw1.4  !ena   10G  FD  No
(qemu) info rocker-of-dpa-flows sw1
prio tbl hits key(mask) --> actions
2    60       pport 1 vlan 1 LLDP src 00:02:00:00:02:00 dst 01:80:c2:00:00:0e
2    60       pport 1 vlan 1 ARP src 00:02:00:00:02:00 dst 00:02:00:00:03:00
2    60       pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:00:02 proto 58
3    50       vlan 2 dst 33:33:ff:00:00:02 --> write group 0x32000001 goto tbl 60
2    60       pport 2 vlan 2 IPv6 src 00:02:00:00:03:00 dst 33:33:ff:00:03:00 proto 58
3    50  1    vlan 2 dst 33:33:ff:00:03:00 --> write group 0x32000001 goto tbl 60
2    60       pport 2 vlan 2 ARP src 00:02:00:00:03:00 dst 00:02:00:00:02:00
3    50  2    vlan 2 dst 00:02:00:00:02:00 --> write group 0x02000001 goto tbl 60
2    60  1    pport 2 vlan 2 IP src 00:02:00:00:03:00 dst 00:02:00:00:02:00 proto 1
3    50  2    vlan 1 dst 00:02:00:00:03:00 --> write group 0x01000002 goto tbl 60
2    60  1    pport 1 vlan 1 IP src 00:02:00:00:02:00 dst 00:02:00:00:03:00 proto 1
2    60       pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:00:01 proto 58
3    50       vlan 1 dst 33:33:ff:00:00:01 --> write group 0x31000000 goto tbl 60
2    60       pport 1 vlan 1 IPv6 src 00:02:00:00:02:00 dst 33:33:ff:00:02:00 proto 58
3    50  1    vlan 1 dst 33:33:ff:00:02:00 --> write group 0x31000000 goto tbl 60
1    60  173  pport 2 vlan 2 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x02000000
1    60  6    pport 2 vlan 2 IPv6 src <any> dst <any> --> write group 0x02000000
1    60  174  pport 1 vlan 1 LLDP src <any> dst 01:80:c2:00:00:0e --> write group 0x01000000
1    60  174  pport 2 vlan 2 IP src <any> dst <any> --> write group 0x02000000
1    60  6    pport 1 vlan 1 IPv6 src <any> dst <any> --> write group 0x01000000
1    60  181  pport 2 vlan 2 ARP src <any> dst <any> --> write group 0x02000000
1    10  715  pport 2 --> apply new vlan 2 goto tbl 20
1    60  177  pport 1 vlan 1 ARP src <any> dst <any> --> write group 0x01000000
1    60  174  pport 1 vlan 1 IP src <any> dst <any> --> write group 0x01000000
1    10  717  pport 1 --> apply new vlan 1 goto tbl 20
1    0   1432 pport 0(0xffff) --> goto tbl 10
(qemu) info rocker-of-dpa-groups sw1
id (decode) --> buckets
0x32000001 (type L2 multicast vlan 2 index 1) --> groups [0x02000001,0x02000000]
0x02000001 (type L2 interface vlan 2 pport 1) --> pop vlan out pport 1
0x01000002 (type L2 interface vlan 1 pport 2) --> pop vlan out pport 2
0x02000000 (type L2 interface vlan 2 pport 0) --> pop vlan out pport 0
0x01000000 (type L2 interface vlan 1 pport 0) --> pop vlan out pport 0
0x31000000 (type L2 multicast vlan 1 index 0) --> groups [0x01000002,0x01000000]
[Added "query-" prefixes to rocker.json commands as suggested by Eric
Blake <eblake@redhat.com>.
--Stefan]
Signed-off-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: Jiri Pirko <jiri@resnulli.us>
Message-id: 1433985681-56138-5-git-send-email-sfeldma@gmail.com
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									5ff1547b75
								
							
						
					
					
						commit
						fafa4d508b
					
				| @ -1798,6 +1798,30 @@ STEXI | ||||
| show available trace events and their state | ||||
| ETEXI | ||||
| 
 | ||||
| STEXI | ||||
| @item rocker @var{name} | ||||
| @findex rocker | ||||
| Show Rocker(s) | ||||
| ETEXI | ||||
| 
 | ||||
| STEXI | ||||
| @item rocker_ports @var{name} | ||||
| @findex rocker_ports | ||||
| Show Rocker ports | ||||
| ETEXI | ||||
| 
 | ||||
| STEXI | ||||
| @item rocker_of_dpa_flows @var{name} [@var{tbl_id}] | ||||
| @findex rocker_of_dpa_flows | ||||
| Show Rocker OF-DPA flow tables | ||||
| ETEXI | ||||
| 
 | ||||
| STEXI | ||||
| @item rocker_of_dpa_groups @var{name} [@var{type}] | ||||
| @findex rocker_of_dpa_groups | ||||
| Show Rocker OF-DPA groups | ||||
| ETEXI | ||||
| 
 | ||||
| STEXI | ||||
| @end table | ||||
| ETEXI | ||||
|  | ||||
							
								
								
									
										303
									
								
								hmp.c
									
									
									
									
									
								
							
							
						
						
									
										303
									
								
								hmp.c
									
									
									
									
									
								
							| @ -15,6 +15,7 @@ | ||||
| 
 | ||||
| #include "hmp.h" | ||||
| #include "net/net.h" | ||||
| #include "net/eth.h" | ||||
| #include "sysemu/char.h" | ||||
| #include "sysemu/block-backend.h" | ||||
| #include "qemu/option.h" | ||||
| @ -1999,3 +2000,305 @@ void hmp_qom_set(Monitor *mon, const QDict *qdict) | ||||
|     } | ||||
|     hmp_handle_error(mon, &err); | ||||
| } | ||||
| 
 | ||||
| void hmp_rocker(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     RockerSwitch *rocker; | ||||
|     Error *errp = NULL; | ||||
| 
 | ||||
|     rocker = qmp_query_rocker(name, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     monitor_printf(mon, "name: %s\n", rocker->name); | ||||
|     monitor_printf(mon, "id: 0x%" PRIx64 "\n", rocker->id); | ||||
|     monitor_printf(mon, "ports: %d\n", rocker->ports); | ||||
| 
 | ||||
|     qapi_free_RockerSwitch(rocker); | ||||
| } | ||||
| 
 | ||||
| void hmp_rocker_ports(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     RockerPortList *list, *port; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     Error *errp = NULL; | ||||
| 
 | ||||
|     list = qmp_query_rocker_ports(name, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     monitor_printf(mon, "            ena/    speed/ auto\n"); | ||||
|     monitor_printf(mon, "      port  link    duplex neg?\n"); | ||||
| 
 | ||||
|     for (port = list; port; port = port->next) { | ||||
|         monitor_printf(mon, "%10s  %-4s   %-3s  %2s  %-3s\n", | ||||
|                        port->value->name, | ||||
|                        port->value->enabled ? port->value->link_up ? | ||||
|                        "up" : "down" : "!ena", | ||||
|                        port->value->speed == 10000 ? "10G" : "??", | ||||
|                        port->value->duplex ? "FD" : "HD", | ||||
|                        port->value->autoneg ? "Yes" : "No"); | ||||
|     } | ||||
| 
 | ||||
|     qapi_free_RockerPortList(list); | ||||
| } | ||||
| 
 | ||||
| void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     RockerOfDpaFlowList *list, *info; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     uint32_t tbl_id = qdict_get_try_int(qdict, "tbl_id", -1); | ||||
|     Error *errp = NULL; | ||||
| 
 | ||||
|     list = qmp_query_rocker_of_dpa_flows(name, tbl_id != -1, tbl_id, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     monitor_printf(mon, "prio tbl hits key(mask) --> actions\n"); | ||||
| 
 | ||||
|     for (info = list; info; info = info->next) { | ||||
|         RockerOfDpaFlow *flow = info->value; | ||||
|         RockerOfDpaFlowKey *key = flow->key; | ||||
|         RockerOfDpaFlowMask *mask = flow->mask; | ||||
|         RockerOfDpaFlowAction *action = flow->action; | ||||
| 
 | ||||
|         if (flow->hits) { | ||||
|             monitor_printf(mon, "%-4d %-3d %-4" PRIu64, | ||||
|                            key->priority, key->tbl_id, flow->hits); | ||||
|         } else { | ||||
|             monitor_printf(mon, "%-4d %-3d     ", | ||||
|                            key->priority, key->tbl_id); | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_in_pport) { | ||||
|             monitor_printf(mon, " pport %d", key->in_pport); | ||||
|             if (mask->has_in_pport) { | ||||
|                 monitor_printf(mon, "(0x%x)", mask->in_pport); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_vlan_id) { | ||||
|             monitor_printf(mon, " vlan %d", | ||||
|                            key->vlan_id & VLAN_VID_MASK); | ||||
|             if (mask->has_vlan_id) { | ||||
|                 monitor_printf(mon, "(0x%x)", mask->vlan_id); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_tunnel_id) { | ||||
|             monitor_printf(mon, " tunnel %d", key->tunnel_id); | ||||
|             if (mask->has_tunnel_id) { | ||||
|                 monitor_printf(mon, "(0x%x)", mask->tunnel_id); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_eth_type) { | ||||
|             switch (key->eth_type) { | ||||
|             case 0x0806: | ||||
|                 monitor_printf(mon, " ARP"); | ||||
|                 break; | ||||
|             case 0x0800: | ||||
|                 monitor_printf(mon, " IP"); | ||||
|                 break; | ||||
|             case 0x86dd: | ||||
|                 monitor_printf(mon, " IPv6"); | ||||
|                 break; | ||||
|             case 0x8809: | ||||
|                 monitor_printf(mon, " LACP"); | ||||
|                 break; | ||||
|             case 0x88cc: | ||||
|                 monitor_printf(mon, " LLDP"); | ||||
|                 break; | ||||
|             default: | ||||
|                 monitor_printf(mon, " eth type 0x%04x", key->eth_type); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_eth_src) { | ||||
|             if ((strcmp(key->eth_src, "01:00:00:00:00:00") == 0) && | ||||
|                 (mask->has_eth_src) && | ||||
|                 (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { | ||||
|                 monitor_printf(mon, " src <any mcast/bcast>"); | ||||
|             } else if ((strcmp(key->eth_src, "00:00:00:00:00:00") == 0) && | ||||
|                 (mask->has_eth_src) && | ||||
|                 (strcmp(mask->eth_src, "01:00:00:00:00:00") == 0)) { | ||||
|                 monitor_printf(mon, " src <any ucast>"); | ||||
|             } else { | ||||
|                 monitor_printf(mon, " src %s", key->eth_src); | ||||
|                 if (mask->has_eth_src) { | ||||
|                     monitor_printf(mon, "(%s)", mask->eth_src); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_eth_dst) { | ||||
|             if ((strcmp(key->eth_dst, "01:00:00:00:00:00") == 0) && | ||||
|                 (mask->has_eth_dst) && | ||||
|                 (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { | ||||
|                 monitor_printf(mon, " dst <any mcast/bcast>"); | ||||
|             } else if ((strcmp(key->eth_dst, "00:00:00:00:00:00") == 0) && | ||||
|                 (mask->has_eth_dst) && | ||||
|                 (strcmp(mask->eth_dst, "01:00:00:00:00:00") == 0)) { | ||||
|                 monitor_printf(mon, " dst <any ucast>"); | ||||
|             } else { | ||||
|                 monitor_printf(mon, " dst %s", key->eth_dst); | ||||
|                 if (mask->has_eth_dst) { | ||||
|                     monitor_printf(mon, "(%s)", mask->eth_dst); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_ip_proto) { | ||||
|             monitor_printf(mon, " proto %d", key->ip_proto); | ||||
|             if (mask->has_ip_proto) { | ||||
|                 monitor_printf(mon, "(0x%x)", mask->ip_proto); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_ip_tos) { | ||||
|             monitor_printf(mon, " TOS %d", key->ip_tos); | ||||
|             if (mask->has_ip_tos) { | ||||
|                 monitor_printf(mon, "(0x%x)", mask->ip_tos); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (key->has_ip_dst) { | ||||
|             monitor_printf(mon, " dst %s", key->ip_dst); | ||||
|         } | ||||
| 
 | ||||
|         if (action->has_goto_tbl || action->has_group_id || | ||||
|             action->has_new_vlan_id) { | ||||
|             monitor_printf(mon, " -->"); | ||||
|         } | ||||
| 
 | ||||
|         if (action->has_new_vlan_id) { | ||||
|             monitor_printf(mon, " apply new vlan %d", | ||||
|                            ntohs(action->new_vlan_id)); | ||||
|         } | ||||
| 
 | ||||
|         if (action->has_group_id) { | ||||
|             monitor_printf(mon, " write group 0x%08x", action->group_id); | ||||
|         } | ||||
| 
 | ||||
|         if (action->has_goto_tbl) { | ||||
|             monitor_printf(mon, " goto tbl %d", action->goto_tbl); | ||||
|         } | ||||
| 
 | ||||
|         monitor_printf(mon, "\n"); | ||||
|     } | ||||
| 
 | ||||
|     qapi_free_RockerOfDpaFlowList(list); | ||||
| } | ||||
| 
 | ||||
| void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict) | ||||
| { | ||||
|     RockerOfDpaGroupList *list, *g; | ||||
|     const char *name = qdict_get_str(qdict, "name"); | ||||
|     uint8_t type = qdict_get_try_int(qdict, "type", 9); | ||||
|     Error *errp = NULL; | ||||
|     bool set = false; | ||||
| 
 | ||||
|     list = qmp_query_rocker_of_dpa_groups(name, type != 9, type, &errp); | ||||
|     if (errp != NULL) { | ||||
|         hmp_handle_error(mon, &errp); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     monitor_printf(mon, "id (decode) --> buckets\n"); | ||||
| 
 | ||||
|     for (g = list; g; g = g->next) { | ||||
|         RockerOfDpaGroup *group = g->value; | ||||
| 
 | ||||
|         monitor_printf(mon, "0x%08x", group->id); | ||||
| 
 | ||||
|         monitor_printf(mon, " (type %s", group->type == 0 ? "L2 interface" : | ||||
|                                          group->type == 1 ? "L2 rewrite" : | ||||
|                                          group->type == 2 ? "L3 unicast" : | ||||
|                                          group->type == 3 ? "L2 multicast" : | ||||
|                                          group->type == 4 ? "L2 flood" : | ||||
|                                          group->type == 5 ? "L3 interface" : | ||||
|                                          group->type == 6 ? "L3 multicast" : | ||||
|                                          group->type == 7 ? "L3 ECMP" : | ||||
|                                          group->type == 8 ? "L2 overlay" : | ||||
|                                          "unknown"); | ||||
| 
 | ||||
|         if (group->has_vlan_id) { | ||||
|             monitor_printf(mon, " vlan %d", group->vlan_id); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_pport) { | ||||
|             monitor_printf(mon, " pport %d", group->pport); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_index) { | ||||
|             monitor_printf(mon, " index %d", group->index); | ||||
|         } | ||||
| 
 | ||||
|         monitor_printf(mon, ") -->"); | ||||
| 
 | ||||
|         if (group->has_set_vlan_id && group->set_vlan_id) { | ||||
|             set = true; | ||||
|             monitor_printf(mon, " set vlan %d", | ||||
|                            group->set_vlan_id & VLAN_VID_MASK); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_set_eth_src) { | ||||
|             if (!set) { | ||||
|                 set = true; | ||||
|                 monitor_printf(mon, " set"); | ||||
|             } | ||||
|             monitor_printf(mon, " src %s", group->set_eth_src); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_set_eth_dst) { | ||||
|             if (!set) { | ||||
|                 set = true; | ||||
|                 monitor_printf(mon, " set"); | ||||
|             } | ||||
|             monitor_printf(mon, " dst %s", group->set_eth_dst); | ||||
|         } | ||||
| 
 | ||||
|         set = false; | ||||
| 
 | ||||
|         if (group->has_ttl_check && group->ttl_check) { | ||||
|             monitor_printf(mon, " check TTL"); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_group_id && group->group_id) { | ||||
|             monitor_printf(mon, " group id 0x%08x", group->group_id); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_pop_vlan && group->pop_vlan) { | ||||
|             monitor_printf(mon, " pop vlan"); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_out_pport) { | ||||
|             monitor_printf(mon, " out pport %d", group->out_pport); | ||||
|         } | ||||
| 
 | ||||
|         if (group->has_group_ids) { | ||||
|             struct uint32List *id; | ||||
| 
 | ||||
|             monitor_printf(mon, " groups ["); | ||||
|             for (id = group->group_ids; id; id = id->next) { | ||||
|                 monitor_printf(mon, "0x%08x", id->value); | ||||
|                 if (id->next) { | ||||
|                     monitor_printf(mon, ","); | ||||
|                 } | ||||
|             } | ||||
|             monitor_printf(mon, "]"); | ||||
|         } | ||||
| 
 | ||||
|         monitor_printf(mon, "\n"); | ||||
|     } | ||||
| 
 | ||||
|     qapi_free_RockerOfDpaGroupList(list); | ||||
| } | ||||
|  | ||||
							
								
								
									
										4
									
								
								hmp.h
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								hmp.h
									
									
									
									
									
								
							| @ -124,5 +124,9 @@ void host_net_remove_completion(ReadLineState *rs, int nb_args, | ||||
|                                 const char *str); | ||||
| void delvm_completion(ReadLineState *rs, int nb_args, const char *str); | ||||
| void loadvm_completion(ReadLineState *rs, int nb_args, const char *str); | ||||
| void hmp_rocker(Monitor *mon, const QDict *qdict); | ||||
| void hmp_rocker_ports(Monitor *mon, const QDict *qdict); | ||||
| void hmp_rocker_of_dpa_flows(Monitor *mon, const QDict *qdict); | ||||
| void hmp_rocker_of_dpa_groups(Monitor *mon, const QDict *qdict); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -39,3 +39,4 @@ obj-$(CONFIG_ETSEC) += fsl_etsec/etsec.o fsl_etsec/registers.o \ | ||||
| common-obj-$(CONFIG_ROCKER) += rocker/rocker.o rocker/rocker_fp.o \
 | ||||
|                                rocker/rocker_desc.o rocker/rocker_world.o \
 | ||||
|                                rocker/rocker_of_dpa.o | ||||
| obj-$(call lnot,$(CONFIG_ROCKER)) += rocker/qmp-norocker.o | ||||
|  | ||||
							
								
								
									
										50
									
								
								hw/net/rocker/qmp-norocker.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								hw/net/rocker/qmp-norocker.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,50 @@ | ||||
| /*
 | ||||
|  * QMP Target options - Commands handled based on a target config | ||||
|  *                      versus a host config | ||||
|  * | ||||
|  * Copyright (c) 2015 David Ahern <dsahern@gmail.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
|  * GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include "qemu-common.h" | ||||
| #include "qmp-commands.h" | ||||
| #include "qapi/qmp/qerror.h" | ||||
| 
 | ||||
| RockerSwitch *qmp_query_rocker(const char *name, Error **errp) | ||||
| { | ||||
|     error_set(errp, QERR_FEATURE_DISABLED, "rocker"); | ||||
|     return NULL; | ||||
| }; | ||||
| 
 | ||||
| RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) | ||||
| { | ||||
|     error_set(errp, QERR_FEATURE_DISABLED, "rocker"); | ||||
|     return NULL; | ||||
| }; | ||||
| 
 | ||||
| RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, | ||||
|                                                    bool has_tbl_id, | ||||
|                                                    uint32_t tbl_id, | ||||
|                                                    Error **errp) | ||||
| { | ||||
|     error_set(errp, QERR_FEATURE_DISABLED, "rocker"); | ||||
|     return NULL; | ||||
| }; | ||||
| 
 | ||||
| RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, | ||||
|                                                      bool has_type, | ||||
|                                                      uint8_t type, | ||||
|                                                      Error **errp) | ||||
| { | ||||
|     error_set(errp, QERR_FEATURE_DISABLED, "rocker"); | ||||
|     return NULL; | ||||
| }; | ||||
| @ -94,6 +94,51 @@ World *rocker_get_world(Rocker *r, enum rocker_world_type type) | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| RockerSwitch *qmp_query_rocker(const char *name, Error **errp) | ||||
| { | ||||
|     RockerSwitch *rocker = g_malloc0(sizeof(*rocker)); | ||||
|     Rocker *r; | ||||
| 
 | ||||
|     r = rocker_find(name); | ||||
|     if (!r) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s not found", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     rocker->name = g_strdup(r->name); | ||||
|     rocker->id = r->switch_id; | ||||
|     rocker->ports = r->fp_ports; | ||||
| 
 | ||||
|     return rocker; | ||||
| } | ||||
| 
 | ||||
| RockerPortList *qmp_query_rocker_ports(const char *name, Error **errp) | ||||
| { | ||||
|     RockerPortList *list = NULL; | ||||
|     Rocker *r; | ||||
|     int i; | ||||
| 
 | ||||
|     r = rocker_find(name); | ||||
|     if (!r) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s not found", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     for (i = r->fp_ports - 1; i >= 0; i--) { | ||||
|         RockerPortList *info = g_malloc0(sizeof(*info)); | ||||
|         info->value = g_malloc0(sizeof(*info->value)); | ||||
|         struct fp_port *port = r->fp_port[i]; | ||||
| 
 | ||||
|         fp_port_get_info(port, info); | ||||
|         info->next = list; | ||||
|         list = info; | ||||
|     } | ||||
| 
 | ||||
|     return list; | ||||
| } | ||||
| 
 | ||||
| uint32_t rocker_fp_ports(Rocker *r) | ||||
| { | ||||
|     return r->fp_ports; | ||||
|  | ||||
| @ -51,6 +51,16 @@ bool fp_port_get_link_up(FpPort *port) | ||||
|     return !qemu_get_queue(port->nic)->link_down; | ||||
| } | ||||
| 
 | ||||
| void fp_port_get_info(FpPort *port, RockerPortList *info) | ||||
| { | ||||
|     info->value->name = g_strdup(port->name); | ||||
|     info->value->enabled = port->enabled; | ||||
|     info->value->link_up = fp_port_get_link_up(port); | ||||
|     info->value->speed = port->speed; | ||||
|     info->value->duplex = port->duplex; | ||||
|     info->value->autoneg = port->autoneg; | ||||
| } | ||||
| 
 | ||||
| void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr) | ||||
| { | ||||
|     memcpy(macaddr->a, port->conf.macaddr.a, sizeof(macaddr->a)); | ||||
|  | ||||
| @ -28,6 +28,7 @@ int fp_port_eg(FpPort *port, const struct iovec *iov, int iovcnt); | ||||
| 
 | ||||
| char *fp_port_get_name(FpPort *port); | ||||
| bool fp_port_get_link_up(FpPort *port); | ||||
| void fp_port_get_info(FpPort *port, RockerPortList *info); | ||||
| void fp_port_get_macaddr(FpPort *port, MACAddr *macaddr); | ||||
| void fp_port_set_macaddr(FpPort *port, MACAddr *macaddr); | ||||
| uint8_t fp_port_get_learning(FpPort *port); | ||||
|  | ||||
| @ -2302,6 +2302,318 @@ static void of_dpa_uninit(World *world) | ||||
|     g_hash_table_destroy(of_dpa->flow_tbl); | ||||
| } | ||||
| 
 | ||||
| struct of_dpa_flow_fill_context { | ||||
|     RockerOfDpaFlowList *list; | ||||
|     uint32_t tbl_id; | ||||
| }; | ||||
| 
 | ||||
| static void of_dpa_flow_fill(void *cookie, void *value, void *user_data) | ||||
| { | ||||
|     struct of_dpa_flow *flow = value; | ||||
|     struct of_dpa_flow_key *key = &flow->key; | ||||
|     struct of_dpa_flow_key *mask = &flow->mask; | ||||
|     struct of_dpa_flow_fill_context *flow_context = user_data; | ||||
|     RockerOfDpaFlowList *new; | ||||
|     RockerOfDpaFlow *nflow; | ||||
|     RockerOfDpaFlowKey *nkey; | ||||
|     RockerOfDpaFlowMask *nmask; | ||||
|     RockerOfDpaFlowAction *naction; | ||||
| 
 | ||||
|     if (flow_context->tbl_id != -1 && | ||||
|         flow_context->tbl_id != key->tbl_id) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     new = g_malloc0(sizeof(*new)); | ||||
|     nflow = new->value = g_malloc0(sizeof(*nflow)); | ||||
|     nkey = nflow->key = g_malloc0(sizeof(*nkey)); | ||||
|     nmask = nflow->mask = g_malloc0(sizeof(*nmask)); | ||||
|     naction = nflow->action = g_malloc0(sizeof(*naction)); | ||||
| 
 | ||||
|     nflow->cookie = flow->cookie; | ||||
|     nflow->hits = flow->stats.hits; | ||||
|     nkey->priority = flow->priority; | ||||
|     nkey->tbl_id = key->tbl_id; | ||||
| 
 | ||||
|     if (key->in_pport || mask->in_pport) { | ||||
|         nkey->has_in_pport = true; | ||||
|         nkey->in_pport = key->in_pport; | ||||
|     } | ||||
| 
 | ||||
|     if (nkey->has_in_pport && mask->in_pport != 0xffffffff) { | ||||
|         nmask->has_in_pport = true; | ||||
|         nmask->in_pport = mask->in_pport; | ||||
|     } | ||||
| 
 | ||||
|     if (key->eth.vlan_id || mask->eth.vlan_id) { | ||||
|         nkey->has_vlan_id = true; | ||||
|         nkey->vlan_id = ntohs(key->eth.vlan_id); | ||||
|     } | ||||
| 
 | ||||
|     if (nkey->has_vlan_id && mask->eth.vlan_id != 0xffff) { | ||||
|         nmask->has_vlan_id = true; | ||||
|         nmask->vlan_id = ntohs(mask->eth.vlan_id); | ||||
|     } | ||||
| 
 | ||||
|     if (key->tunnel_id || mask->tunnel_id) { | ||||
|         nkey->has_tunnel_id = true; | ||||
|         nkey->tunnel_id = key->tunnel_id; | ||||
|     } | ||||
| 
 | ||||
|     if (nkey->has_tunnel_id && mask->tunnel_id != 0xffffffff) { | ||||
|         nmask->has_tunnel_id = true; | ||||
|         nmask->tunnel_id = mask->tunnel_id; | ||||
|     } | ||||
| 
 | ||||
|     if (memcmp(key->eth.src.a, zero_mac.a, ETH_ALEN) || | ||||
|         memcmp(mask->eth.src.a, zero_mac.a, ETH_ALEN)) { | ||||
|         nkey->has_eth_src = true; | ||||
|         nkey->eth_src = qemu_mac_strdup_printf(key->eth.src.a); | ||||
|     } | ||||
| 
 | ||||
|     if (nkey->has_eth_src && memcmp(mask->eth.src.a, ff_mac.a, ETH_ALEN)) { | ||||
|         nmask->has_eth_src = true; | ||||
|         nmask->eth_src = qemu_mac_strdup_printf(mask->eth.src.a); | ||||
|     } | ||||
| 
 | ||||
|     if (memcmp(key->eth.dst.a, zero_mac.a, ETH_ALEN) || | ||||
|         memcmp(mask->eth.dst.a, zero_mac.a, ETH_ALEN)) { | ||||
|         nkey->has_eth_dst = true; | ||||
|         nkey->eth_dst = qemu_mac_strdup_printf(key->eth.dst.a); | ||||
|     } | ||||
| 
 | ||||
|     if (nkey->has_eth_dst && memcmp(mask->eth.dst.a, ff_mac.a, ETH_ALEN)) { | ||||
|         nmask->has_eth_dst = true; | ||||
|         nmask->eth_dst = qemu_mac_strdup_printf(mask->eth.dst.a); | ||||
|     } | ||||
| 
 | ||||
|     if (key->eth.type) { | ||||
| 
 | ||||
|         nkey->has_eth_type = true; | ||||
|         nkey->eth_type = ntohs(key->eth.type); | ||||
| 
 | ||||
|         switch (ntohs(key->eth.type)) { | ||||
|         case 0x0800: | ||||
|         case 0x86dd: | ||||
|             if (key->ip.proto || mask->ip.proto) { | ||||
|                 nkey->has_ip_proto = true; | ||||
|                 nkey->ip_proto = key->ip.proto; | ||||
|             } | ||||
|             if (nkey->has_ip_proto && mask->ip.proto != 0xff) { | ||||
|                 nmask->has_ip_proto = true; | ||||
|                 nmask->ip_proto = mask->ip.proto; | ||||
|             } | ||||
|             if (key->ip.tos || mask->ip.tos) { | ||||
|                 nkey->has_ip_tos = true; | ||||
|                 nkey->ip_tos = key->ip.tos; | ||||
|             } | ||||
|             if (nkey->has_ip_tos && mask->ip.tos != 0xff) { | ||||
|                 nmask->has_ip_tos = true; | ||||
|                 nmask->ip_tos = mask->ip.tos; | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         switch (ntohs(key->eth.type)) { | ||||
|         case 0x0800: | ||||
|             if (key->ipv4.addr.dst || mask->ipv4.addr.dst) { | ||||
|                 char *dst = inet_ntoa(*(struct in_addr *)&key->ipv4.addr.dst); | ||||
|                 int dst_len = of_dpa_mask2prefix(mask->ipv4.addr.dst); | ||||
|                 nkey->has_ip_dst = true; | ||||
|                 nkey->ip_dst = g_strdup_printf("%s/%d", dst, dst_len); | ||||
|             } | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (flow->action.goto_tbl) { | ||||
|         naction->has_goto_tbl = true; | ||||
|         naction->goto_tbl = flow->action.goto_tbl; | ||||
|     } | ||||
| 
 | ||||
|     if (flow->action.write.group_id) { | ||||
|         naction->has_group_id = true; | ||||
|         naction->group_id = flow->action.write.group_id; | ||||
|     } | ||||
| 
 | ||||
|     if (flow->action.apply.new_vlan_id) { | ||||
|         naction->has_new_vlan_id = true; | ||||
|         naction->new_vlan_id = flow->action.apply.new_vlan_id; | ||||
|     } | ||||
| 
 | ||||
|     new->next = flow_context->list; | ||||
|     flow_context->list = new; | ||||
| } | ||||
| 
 | ||||
| RockerOfDpaFlowList *qmp_query_rocker_of_dpa_flows(const char *name, | ||||
|                                                    bool has_tbl_id, | ||||
|                                                    uint32_t tbl_id, | ||||
|                                                    Error **errp) | ||||
| { | ||||
|     struct rocker *r; | ||||
|     struct world *w; | ||||
|     struct of_dpa *of_dpa; | ||||
|     struct of_dpa_flow_fill_context fill_context = { | ||||
|         .list = NULL, | ||||
|         .tbl_id = tbl_id, | ||||
|     }; | ||||
| 
 | ||||
|     r = rocker_find(name); | ||||
|     if (!r) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s not found", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); | ||||
|     if (!w) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s doesn't have OF-DPA world", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     of_dpa = world_private(w); | ||||
| 
 | ||||
|     g_hash_table_foreach(of_dpa->flow_tbl, of_dpa_flow_fill, &fill_context); | ||||
| 
 | ||||
|     return fill_context.list; | ||||
| } | ||||
| 
 | ||||
| struct of_dpa_group_fill_context { | ||||
|     RockerOfDpaGroupList *list; | ||||
|     uint8_t type; | ||||
| }; | ||||
| 
 | ||||
| static void of_dpa_group_fill(void *key, void *value, void *user_data) | ||||
| { | ||||
|     struct of_dpa_group *group = value; | ||||
|     struct of_dpa_group_fill_context *flow_context = user_data; | ||||
|     RockerOfDpaGroupList *new; | ||||
|     RockerOfDpaGroup *ngroup; | ||||
|     struct uint32List *id; | ||||
|     int i; | ||||
| 
 | ||||
|     if (flow_context->type != 9 && | ||||
|         flow_context->type != ROCKER_GROUP_TYPE_GET(group->id)) { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     new = g_malloc0(sizeof(*new)); | ||||
|     ngroup = new->value = g_malloc0(sizeof(*ngroup)); | ||||
| 
 | ||||
|     ngroup->id = group->id; | ||||
| 
 | ||||
|     ngroup->type = ROCKER_GROUP_TYPE_GET(group->id); | ||||
| 
 | ||||
|     switch (ngroup->type) { | ||||
|     case ROCKER_OF_DPA_GROUP_TYPE_L2_INTERFACE: | ||||
|         ngroup->has_vlan_id = true; | ||||
|         ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); | ||||
|         ngroup->has_pport = true; | ||||
|         ngroup->pport = ROCKER_GROUP_PORT_GET(group->id); | ||||
|         ngroup->has_out_pport = true; | ||||
|         ngroup->out_pport = group->l2_interface.out_pport; | ||||
|         ngroup->has_pop_vlan = true; | ||||
|         ngroup->pop_vlan = group->l2_interface.pop_vlan; | ||||
|         break; | ||||
|     case ROCKER_OF_DPA_GROUP_TYPE_L2_REWRITE: | ||||
|         ngroup->has_index = true; | ||||
|         ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); | ||||
|         ngroup->has_group_id = true; | ||||
|         ngroup->group_id = group->l2_rewrite.group_id; | ||||
|         if (group->l2_rewrite.vlan_id) { | ||||
|             ngroup->has_set_vlan_id = true; | ||||
|             ngroup->set_vlan_id = ntohs(group->l2_rewrite.vlan_id); | ||||
|         } | ||||
|         break; | ||||
|         if (memcmp(group->l2_rewrite.src_mac.a, zero_mac.a, ETH_ALEN)) { | ||||
|             ngroup->has_set_eth_src = true; | ||||
|             ngroup->set_eth_src = | ||||
|                 qemu_mac_strdup_printf(group->l2_rewrite.src_mac.a); | ||||
|         } | ||||
|         if (memcmp(group->l2_rewrite.dst_mac.a, zero_mac.a, ETH_ALEN)) { | ||||
|             ngroup->has_set_eth_dst = true; | ||||
|             ngroup->set_eth_dst = | ||||
|                 qemu_mac_strdup_printf(group->l2_rewrite.dst_mac.a); | ||||
|         } | ||||
|     case ROCKER_OF_DPA_GROUP_TYPE_L2_FLOOD: | ||||
|     case ROCKER_OF_DPA_GROUP_TYPE_L2_MCAST: | ||||
|         ngroup->has_vlan_id = true; | ||||
|         ngroup->vlan_id = ROCKER_GROUP_VLAN_GET(group->id); | ||||
|         ngroup->has_index = true; | ||||
|         ngroup->index = ROCKER_GROUP_INDEX_GET(group->id); | ||||
|         for (i = 0; i < group->l2_flood.group_count; i++) { | ||||
|             ngroup->has_group_ids = true; | ||||
|             id = g_malloc0(sizeof(*id)); | ||||
|             id->value = group->l2_flood.group_ids[i]; | ||||
|             id->next = ngroup->group_ids; | ||||
|             ngroup->group_ids = id; | ||||
|         } | ||||
|         break; | ||||
|     case ROCKER_OF_DPA_GROUP_TYPE_L3_UCAST: | ||||
|         ngroup->has_index = true; | ||||
|         ngroup->index = ROCKER_GROUP_INDEX_LONG_GET(group->id); | ||||
|         ngroup->has_group_id = true; | ||||
|         ngroup->group_id = group->l3_unicast.group_id; | ||||
|         if (group->l3_unicast.vlan_id) { | ||||
|             ngroup->has_set_vlan_id = true; | ||||
|             ngroup->set_vlan_id = ntohs(group->l3_unicast.vlan_id); | ||||
|         } | ||||
|         if (memcmp(group->l3_unicast.src_mac.a, zero_mac.a, ETH_ALEN)) { | ||||
|             ngroup->has_set_eth_src = true; | ||||
|             ngroup->set_eth_src = | ||||
|                 qemu_mac_strdup_printf(group->l3_unicast.src_mac.a); | ||||
|         } | ||||
|         if (memcmp(group->l3_unicast.dst_mac.a, zero_mac.a, ETH_ALEN)) { | ||||
|             ngroup->has_set_eth_dst = true; | ||||
|             ngroup->set_eth_dst = | ||||
|                 qemu_mac_strdup_printf(group->l3_unicast.dst_mac.a); | ||||
|         } | ||||
|         if (group->l3_unicast.ttl_check) { | ||||
|             ngroup->has_ttl_check = true; | ||||
|             ngroup->ttl_check = group->l3_unicast.ttl_check; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| 
 | ||||
|     new->next = flow_context->list; | ||||
|     flow_context->list = new; | ||||
| } | ||||
| 
 | ||||
| RockerOfDpaGroupList *qmp_query_rocker_of_dpa_groups(const char *name, | ||||
|                                                      bool has_type, | ||||
|                                                      uint8_t type, | ||||
|                                                      Error **errp) | ||||
| { | ||||
|     struct rocker *r; | ||||
|     struct world *w; | ||||
|     struct of_dpa *of_dpa; | ||||
|     struct of_dpa_group_fill_context fill_context = { | ||||
|         .list = NULL, | ||||
|         .type = type, | ||||
|     }; | ||||
| 
 | ||||
|     r = rocker_find(name); | ||||
|     if (!r) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s not found", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     w = rocker_get_world(r, ROCKER_WORLD_TYPE_OF_DPA); | ||||
|     if (!w) { | ||||
|         error_set(errp, ERROR_CLASS_GENERIC_ERROR, | ||||
|                   "rocker %s doesn't have OF-DPA world", name); | ||||
|         return NULL; | ||||
|     } | ||||
| 
 | ||||
|     of_dpa = world_private(w); | ||||
| 
 | ||||
|     g_hash_table_foreach(of_dpa->group_tbl, of_dpa_group_fill, &fill_context); | ||||
| 
 | ||||
|     return fill_context.list; | ||||
| } | ||||
| 
 | ||||
| static WorldOps of_dpa_ops = { | ||||
|     .init = of_dpa_init, | ||||
|     .uninit = of_dpa_uninit, | ||||
|  | ||||
							
								
								
									
										28
									
								
								monitor.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								monitor.c
									
									
									
									
									
								
							| @ -2862,6 +2862,34 @@ static mon_cmd_t info_cmds[] = { | ||||
|         .help       = "show memory devices", | ||||
|         .mhandler.cmd = hmp_info_memory_devices, | ||||
|     }, | ||||
|     { | ||||
|         .name       = "rocker", | ||||
|         .args_type  = "name:s", | ||||
|         .params     = "name", | ||||
|         .help       = "Show rocker switch", | ||||
|         .mhandler.cmd = hmp_rocker, | ||||
|     }, | ||||
|     { | ||||
|         .name       = "rocker-ports", | ||||
|         .args_type  = "name:s", | ||||
|         .params     = "name", | ||||
|         .help       = "Show rocker ports", | ||||
|         .mhandler.cmd = hmp_rocker_ports, | ||||
|     }, | ||||
|     { | ||||
|         .name       = "rocker-of-dpa-flows", | ||||
|         .args_type  = "name:s,tbl_id:i?", | ||||
|         .params     = "name [tbl_id]", | ||||
|         .help       = "Show rocker OF-DPA flow tables", | ||||
|         .mhandler.cmd = hmp_rocker_of_dpa_flows, | ||||
|     }, | ||||
|     { | ||||
|         .name       = "rocker-of-dpa-groups", | ||||
|         .args_type  = "name:s,type:i?", | ||||
|         .params     = "name [type]", | ||||
|         .help       = "Show rocker OF-DPA groups", | ||||
|         .mhandler.cmd = hmp_rocker_of_dpa_groups, | ||||
|     }, | ||||
|     { | ||||
|         .name       = NULL, | ||||
|     }, | ||||
|  | ||||
| @ -3788,3 +3788,6 @@ | ||||
| # Since: 2.1 | ||||
| ## | ||||
| { 'command': 'rtc-reset-reinjection' } | ||||
| 
 | ||||
| # Rocker ethernet network switch | ||||
| { 'include': 'qapi/rocker.json' } | ||||
|  | ||||
							
								
								
									
										286
									
								
								qapi/rocker.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								qapi/rocker.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,286 @@ | ||||
| ## | ||||
| # @Rocker: | ||||
| # | ||||
| # Rocker switch information. | ||||
| # | ||||
| # @name: switch name | ||||
| # | ||||
| # @id: switch ID | ||||
| # | ||||
| # @ports: number of front-panel ports | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerSwitch', | ||||
|   'data': { 'name': 'str', 'id': 'uint64', 'ports': 'uint32' } } | ||||
| 
 | ||||
| ## | ||||
| # @query-rocker: | ||||
| # | ||||
| # Return rocker switch information. | ||||
| # | ||||
| # Returns: @Rocker information | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'command': 'query-rocker', | ||||
|   'data': { 'name': 'str' }, | ||||
|   'returns': 'RockerSwitch' } | ||||
| 
 | ||||
| ## | ||||
| # @RockerPortDuplex: | ||||
| # | ||||
| # An eumeration of port duplex states. | ||||
| # | ||||
| # @half: half duplex | ||||
| # | ||||
| # @full: full duplex | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'enum': 'RockerPortDuplex', 'data': [ 'half', 'full' ] } | ||||
| 
 | ||||
| ## | ||||
| # @RockerPortAutoneg: | ||||
| # | ||||
| # An eumeration of port autoneg states. | ||||
| # | ||||
| # @off: autoneg is off | ||||
| # | ||||
| # @on: autoneg is on | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'enum': 'RockerPortAutoneg', 'data': [ 'off', 'on' ] } | ||||
| 
 | ||||
| ## | ||||
| # @RockerPort: | ||||
| # | ||||
| # Rocker switch port information. | ||||
| # | ||||
| # @name: port name | ||||
| # | ||||
| # @enabled: port is enabled for I/O | ||||
| # | ||||
| # @link-up: physical link is UP on port | ||||
| # | ||||
| # @speed: port link speed in Mbps | ||||
| # | ||||
| # @duplex: port link duplex | ||||
| # | ||||
| # @autoneg: port link autoneg | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerPort', | ||||
|   'data': { 'name': 'str', 'enabled': 'bool', 'link-up': 'bool', | ||||
|             'speed': 'uint32', 'duplex': 'RockerPortDuplex', | ||||
|             'autoneg': 'RockerPortAutoneg' } } | ||||
| 
 | ||||
| ## | ||||
| # @query-rocker-ports: | ||||
| # | ||||
| # Return rocker switch information. | ||||
| # | ||||
| # Returns: @Rocker information | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'command': 'query-rocker-ports', | ||||
|   'data': { 'name': 'str' }, | ||||
|   'returns': ['RockerPort'] } | ||||
| 
 | ||||
| ## | ||||
| # @RockerOfDpaFlowKey: | ||||
| # | ||||
| # Rocker switch OF-DPA flow key | ||||
| # | ||||
| # @priority: key priority, 0 being lowest priority | ||||
| # | ||||
| # @tbl-id: flow table ID | ||||
| # | ||||
| # @in-pport: #optional physical input port | ||||
| # | ||||
| # @tunnel-id: #optional tunnel ID | ||||
| # | ||||
| # @vlan-id: #optional VLAN ID | ||||
| # | ||||
| # @eth-type: #optional Ethernet header type | ||||
| # | ||||
| # @eth-src: #optional Ethernet header source MAC address | ||||
| # | ||||
| # @eth-dst: #optional Ethernet header destination MAC address | ||||
| # | ||||
| # @ip-proto: #optional IP Header protocol field | ||||
| # | ||||
| # @ip-tos: #optional IP header TOS field | ||||
| # | ||||
| # @ip-dst: #optional IP header destination address | ||||
| # | ||||
| # Note: fields are marked #optional to indicate that they may or may not | ||||
| # appear in the flow key depending if they're relevant to the flow key. | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerOfDpaFlowKey', | ||||
|   'data' : { 'priority': 'uint32', 'tbl-id': 'uint32', '*in-pport': 'uint32', | ||||
|              '*tunnel-id': 'uint32', '*vlan-id': 'uint16', | ||||
|              '*eth-type': 'uint16', '*eth-src': 'str', '*eth-dst': 'str', | ||||
|              '*ip-proto': 'uint8', '*ip-tos': 'uint8', '*ip-dst': 'str' } } | ||||
| 
 | ||||
| ## | ||||
| # @RockerOfDpaFlowMask: | ||||
| # | ||||
| # Rocker switch OF-DPA flow mask | ||||
| # | ||||
| # @in-pport: #optional physical input port | ||||
| # | ||||
| # @tunnel-id: #optional tunnel ID | ||||
| # | ||||
| # @vlan-id: #optional VLAN ID | ||||
| # | ||||
| # @eth-src: #optional Ethernet header source MAC address | ||||
| # | ||||
| # @eth-dst: #optional Ethernet header destination MAC address | ||||
| # | ||||
| # @ip-proto: #optional IP Header protocol field | ||||
| # | ||||
| # @ip-tos: #optional IP header TOS field | ||||
| # | ||||
| # Note: fields are marked #optional to indicate that they may or may not | ||||
| # appear in the flow mask depending if they're relevant to the flow mask. | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerOfDpaFlowMask', | ||||
|   'data' : { '*in-pport': 'uint32', '*tunnel-id': 'uint32', | ||||
|              '*vlan-id': 'uint16', '*eth-src': 'str', '*eth-dst': 'str', | ||||
|              '*ip-proto': 'uint8', '*ip-tos': 'uint8' } } | ||||
| 
 | ||||
| ## | ||||
| # @RockerOfDpaFlowAction: | ||||
| # | ||||
| # Rocker switch OF-DPA flow action | ||||
| # | ||||
| # @goto-tbl: #optional next table ID | ||||
| # | ||||
| # @group-id: #optional group ID | ||||
| # | ||||
| # @tunnel-lport: #optional tunnel logical port ID | ||||
| # | ||||
| # @vlan-id: #optional VLAN ID | ||||
| # | ||||
| # @new-vlan-id: #optional new VLAN ID | ||||
| # | ||||
| # @out-pport: #optional physical output port | ||||
| # | ||||
| # Note: fields are marked #optional to indicate that they may or may not | ||||
| # appear in the flow action depending if they're relevant to the flow action. | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerOfDpaFlowAction', | ||||
|   'data' : { '*goto-tbl': 'uint32', '*group-id': 'uint32', | ||||
|              '*tunnel-lport': 'uint32', '*vlan-id': 'uint16', | ||||
|              '*new-vlan-id': 'uint16', '*out-pport': 'uint32' } } | ||||
| 
 | ||||
| ## | ||||
| # @RockerOfDpaFlow: | ||||
| # | ||||
| # Rocker switch OF-DPA flow | ||||
| # | ||||
| # @cookie: flow unique cookie ID | ||||
| # | ||||
| # @hits: count of matches (hits) on flow | ||||
| # | ||||
| # @key: flow key | ||||
| # | ||||
| # @mask: flow mask | ||||
| # | ||||
| # @action: flow action | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerOfDpaFlow', | ||||
|   'data': { 'cookie': 'uint64', 'hits': 'uint64', 'key': 'RockerOfDpaFlowKey', | ||||
|             'mask': 'RockerOfDpaFlowMask', 'action': 'RockerOfDpaFlowAction' } } | ||||
| 
 | ||||
| ## | ||||
| # @query-rocker-of-dpa-flows: | ||||
| # | ||||
| # Return rocker OF-DPA flow information. | ||||
| # | ||||
| # @name: switch name | ||||
| # | ||||
| # @tbl-id: #optional flow table ID.  If tbl-id is not specified, returns | ||||
| # flow information for all tables. | ||||
| # | ||||
| # Returns: @Rocker OF-DPA flow information | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'command': 'query-rocker-of-dpa-flows', | ||||
|   'data': { 'name': 'str', '*tbl-id': 'uint32' }, | ||||
|   'returns': ['RockerOfDpaFlow'] } | ||||
| 
 | ||||
| ## | ||||
| # @RockerOfDpaGroup: | ||||
| # | ||||
| # Rocker switch OF-DPA group | ||||
| # | ||||
| # @id: group unique ID | ||||
| # | ||||
| # @type: group type | ||||
| # | ||||
| # @vlan-id: #optional VLAN ID | ||||
| # | ||||
| # @pport: #optional physical port number | ||||
| # | ||||
| # @index: #optional group index, unique with group type | ||||
| # | ||||
| # @out-pport: #optional output physical port number | ||||
| # | ||||
| # @group-id: #optional next group ID | ||||
| # | ||||
| # @set-vlan-id: #optional VLAN ID to set | ||||
| # | ||||
| # @pop-vlan: #optional pop VLAN headr from packet | ||||
| # | ||||
| # @group-ids: #optional list of next group IDs | ||||
| # | ||||
| # @set-eth-src: #optional set source MAC address in Ethernet header | ||||
| # | ||||
| # @set-eth-dst: #optional set destination MAC address in Ethernet header | ||||
| # | ||||
| # @ttl-check: #optional perform TTL check | ||||
| # | ||||
| # Note: fields are marked #optional to indicate that they may or may not | ||||
| # appear in the group depending if they're relevant to the group type. | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'struct': 'RockerOfDpaGroup', | ||||
|   'data': { 'id': 'uint32',  'type': 'uint8', '*vlan-id': 'uint16', | ||||
|             '*pport': 'uint32', '*index': 'uint32', '*out-pport': 'uint32', | ||||
|             '*group-id': 'uint32', '*set-vlan-id': 'uint16', | ||||
|             '*pop-vlan': 'uint8', '*group-ids': ['uint32'], | ||||
|             '*set-eth-src': 'str', '*set-eth-dst': 'str', | ||||
|             '*ttl-check': 'uint8' } } | ||||
| 
 | ||||
| ## | ||||
| # @query-rocker-of-dpa-groups: | ||||
| # | ||||
| # Return rocker OF-DPA group information. | ||||
| # | ||||
| # @name: switch name | ||||
| # | ||||
| # @type: #optional group type.  If type is not specified, returns | ||||
| # group information for all group types. | ||||
| # | ||||
| # Returns: @Rocker OF-DPA group information | ||||
| # | ||||
| # Since: 2.4 | ||||
| ## | ||||
| { 'command': 'query-rocker-of-dpa-groups', | ||||
|   'data': { 'name': 'str', '*type': 'uint8' }, | ||||
|   'returns': ['RockerOfDpaGroup'] } | ||||
							
								
								
									
										103
									
								
								qmp-commands.hx
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								qmp-commands.hx
									
									
									
									
									
								
							| @ -4165,3 +4165,106 @@ Example: | ||||
| <- { "return": {} } | ||||
| 
 | ||||
| EQMP | ||||
| 
 | ||||
|     { | ||||
|         .name       = "query-rocker", | ||||
|         .args_type  = "name:s", | ||||
|         .mhandler.cmd_new = qmp_marshal_input_query_rocker, | ||||
|     }, | ||||
| 
 | ||||
| SQMP | ||||
| Show rocker switch | ||||
| ------------------ | ||||
| 
 | ||||
| Arguments: | ||||
| 
 | ||||
| - "name": switch name | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| -> { "execute": "query-rocker", "arguments": { "name": "sw1" } } | ||||
| <- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}} | ||||
| 
 | ||||
| EQMP | ||||
| 
 | ||||
|     { | ||||
|         .name       = "query-rocker-ports", | ||||
|         .args_type  = "name:s", | ||||
|         .mhandler.cmd_new = qmp_marshal_input_query_rocker_ports, | ||||
|     }, | ||||
| 
 | ||||
| SQMP | ||||
| Show rocker switch ports | ||||
| ------------------------ | ||||
| 
 | ||||
| Arguments: | ||||
| 
 | ||||
| - "name": switch name | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| -> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } } | ||||
| <- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1", | ||||
|                   "autoneg": "off", "link-up": true, "speed": 10000}, | ||||
|                  {"duplex": "full", "enabled": true, "name": "sw1.2", | ||||
|                   "autoneg": "off", "link-up": true, "speed": 10000} | ||||
|    ]} | ||||
| 
 | ||||
| EQMP | ||||
| 
 | ||||
|     { | ||||
|         .name       = "query-rocker-of-dpa-flows", | ||||
|         .args_type  = "name:s,tbl-id:i?", | ||||
|         .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_flows, | ||||
|     }, | ||||
| 
 | ||||
| SQMP | ||||
| Show rocker switch OF-DPA flow tables | ||||
| ------------------------------------- | ||||
| 
 | ||||
| Arguments: | ||||
| 
 | ||||
| - "name": switch name | ||||
| - "tbl-id": (optional) flow table ID | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| -> { "execute": "query-rocker-of-dpa-flows", "arguments": { "name": "sw1" } } | ||||
| <- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0}, | ||||
|                   "hits": 138, | ||||
|                   "cookie": 0, | ||||
|                   "action": {"goto-tbl": 10}, | ||||
|                   "mask": {"in-pport": 4294901760} | ||||
|                  }, | ||||
|                  {...more...}, | ||||
|    ]} | ||||
| 
 | ||||
| EQMP | ||||
| 
 | ||||
|     { | ||||
|         .name       = "query-rocker-of-dpa-groups", | ||||
|         .args_type  = "name:s,type:i?", | ||||
|         .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_groups, | ||||
|     }, | ||||
| 
 | ||||
| SQMP | ||||
| Show rocker OF-DPA group tables | ||||
| ------------------------------- | ||||
| 
 | ||||
| Arguments: | ||||
| 
 | ||||
| - "name": switch name | ||||
| - "type": (optional) group type | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| -> { "execute": "query-rocker-of-dpa-groups", "arguments": { "name": "sw1" } } | ||||
| <- { "return": [ {"type": 0, "out-pport": 2, "pport": 2, "vlan-id": 3841, | ||||
|                   "pop-vlan": 1, "id": 251723778}, | ||||
|                  {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3841, | ||||
|                   "pop-vlan": 1, "id": 251723776}, | ||||
|                  {"type": 0, "out-pport": 1, "pport": 1, "vlan-id": 3840, | ||||
|                   "pop-vlan": 1, "id": 251658241}, | ||||
|                  {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840, | ||||
|                   "pop-vlan": 1, "id": 251658240} | ||||
|    ]} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Scott Feldman
						Scott Feldman