github.com/vmware/govmomi@v0.51.0/cli/dvs/portgroup/info.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package portgroup 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "io" 12 "reflect" 13 "sort" 14 "strings" 15 16 "github.com/vmware/govmomi/cli" 17 "github.com/vmware/govmomi/cli/flags" 18 "github.com/vmware/govmomi/object" 19 "github.com/vmware/govmomi/vim25/mo" 20 "github.com/vmware/govmomi/vim25/types" 21 ) 22 23 type info struct { 24 *flags.DatacenterFlag 25 26 pg string 27 active bool 28 connected bool 29 inside bool 30 uplinkPort bool 31 vlanID int 32 count int 33 dvsRules bool 34 } 35 36 var protocols = map[int32]string{ 37 1: "icmp", 38 2: "igmp", 39 6: "tcp", 40 17: "udp", 41 58: "ipv6-icmp", 42 } 43 44 type trafficRule struct { 45 Description string 46 Direction string 47 Action string 48 Protocol string 49 SourceAddress string 50 SourceIpPort string 51 DestinationAddress string 52 DestinationIpPort string 53 } 54 55 func init() { 56 cli.Register("dvs.portgroup.info", &info{}) 57 } 58 59 func (cmd *info) Register(ctx context.Context, f *flag.FlagSet) { 60 cmd.DatacenterFlag, ctx = flags.NewDatacenterFlag(ctx) 61 cmd.DatacenterFlag.Register(ctx, f) 62 63 f.StringVar(&cmd.pg, "pg", "", "Distributed Virtual Portgroup") 64 f.BoolVar(&cmd.active, "active", false, "Filter by port active or inactive status") 65 f.BoolVar(&cmd.connected, "connected", false, "Filter by port connected or disconnected status") 66 f.BoolVar(&cmd.inside, "inside", true, "Filter by port inside or outside status") 67 f.BoolVar(&cmd.uplinkPort, "uplinkPort", false, "Filter for uplink ports") 68 f.IntVar(&cmd.vlanID, "vlan", 0, "Filter by VLAN ID (0 = unfiltered)") 69 f.IntVar(&cmd.count, "count", 0, "Number of matches to return (0 = unlimited)") 70 f.BoolVar(&cmd.dvsRules, "r", false, "Show DVS rules") 71 } 72 73 func (cmd *info) Usage() string { 74 return "DVS" 75 } 76 77 func (cmd *info) Description() string { 78 return `Portgroup info for DVS. 79 80 Examples: 81 govc dvs.portgroup.info DSwitch 82 govc dvs.portgroup.info -pg InternalNetwork DSwitch 83 govc find / -type DistributedVirtualSwitch | xargs -n1 govc dvs.portgroup.info` 84 } 85 86 type infoResult struct { 87 Port []types.DistributedVirtualPort `json:"port"` 88 cmd *info 89 } 90 91 func printPort(port types.BaseDvsIpPort) string { 92 if port != nil { 93 switch portType := port.(type) { 94 case *types.DvsSingleIpPort: 95 return fmt.Sprintf("%d", portType.PortNumber) 96 case *types.DvsIpPortRange: 97 return fmt.Sprintf("%d-%d", portType.StartPortNumber, 98 portType.EndPortNumber) 99 } 100 } 101 return "Any" 102 } 103 104 func printAddress(address types.BaseIpAddress) string { 105 if address != nil { 106 switch (address).(type) { 107 case *types.SingleIp: 108 return address.(*types.SingleIp).Address 109 case *types.IpRange: 110 return fmt.Sprintf("%s/%d", address.(*types.IpRange).AddressPrefix, address.(*types.IpRange).PrefixLength) 111 } 112 } 113 return "Any" 114 } 115 116 func printAction(action types.BaseDvsNetworkRuleAction) string { 117 if action != nil { 118 switch (action).(type) { 119 case *types.DvsAcceptNetworkRuleAction: 120 return fmt.Sprintf("Accept") 121 case *types.DvsDropNetworkRuleAction: 122 return fmt.Sprintf("Drop") 123 } 124 } 125 return "n/a" 126 } 127 128 func printTable(trafficRuleSet map[int]map[int]trafficRule, portID int) { 129 if len(trafficRuleSet[portID]) == 0 { 130 return 131 } 132 133 keys := []int{} 134 for k := range trafficRuleSet[portID] { 135 keys = append(keys, k) 136 } 137 sort.Ints(keys) 138 tabWidthInt := 22 139 tabWidth := fmt.Sprintf("%d", tabWidthInt) 140 headLen := 9*(tabWidthInt+2) - 1 141 fmt.Printf("+" + strings.Repeat("-", headLen) + "+\n") 142 format := "| %-" + tabWidth + 143 "s| %-" + tabWidth + 144 "s| %-" + tabWidth + 145 "s| %-" + tabWidth + 146 "s| %-" + tabWidth + 147 "s| %-" + tabWidth + 148 "s| %-" + tabWidth + 149 "s| %-" + tabWidth + 150 "s| %-" + tabWidth + 151 "s|\n" 152 fmt.Printf(format, 153 "Sequence", 154 "Description", 155 "Direction", 156 "Action", 157 "Protocol", 158 "SourceAddress", 159 "SourceIpPort", 160 "DestinationAddress", 161 "DestinationIpPort") 162 fmt.Printf("+" + strings.Repeat("-", headLen) + "+\n") 163 for _, id := range keys { 164 fmt.Printf(format, 165 fmt.Sprintf("%d", id), 166 trafficRuleSet[portID][id].Description, 167 trafficRuleSet[portID][id].Direction, 168 trafficRuleSet[portID][id].Action, 169 trafficRuleSet[portID][id].Protocol, 170 trafficRuleSet[portID][id].SourceAddress, 171 trafficRuleSet[portID][id].SourceIpPort, 172 trafficRuleSet[portID][id].DestinationAddress, 173 trafficRuleSet[portID][id].DestinationIpPort) 174 } 175 fmt.Printf("+" + strings.Repeat("-", headLen) + "+\n") 176 } 177 178 func (r *infoResult) Write(w io.Writer) error { 179 trafficRuleSet := make(map[int]map[int]trafficRule) 180 for portID, port := range r.Port { 181 var vlanID int32 182 setting := port.Config.Setting.(*types.VMwareDVSPortSetting) 183 184 switch vlan := setting.Vlan.(type) { 185 case *types.VmwareDistributedVirtualSwitchVlanIdSpec: 186 vlanID = vlan.VlanId 187 case *types.VmwareDistributedVirtualSwitchTrunkVlanSpec: 188 case *types.VmwareDistributedVirtualSwitchPvlanSpec: 189 vlanID = vlan.PvlanId 190 } 191 192 // Show port info if: VLAN ID is not defined, or VLAN ID matches requested VLAN 193 if r.cmd.vlanID == 0 || vlanID == int32(r.cmd.vlanID) { 194 fmt.Printf("PortgroupKey: %s\n", port.PortgroupKey) 195 fmt.Printf("DvsUuid: %s\n", port.DvsUuid) 196 fmt.Printf("VlanId: %d\n", vlanID) 197 fmt.Printf("PortKey: %s\n\n", port.Key) 198 199 trafficRuleSet[portID] = make(map[int]trafficRule) 200 201 if r.cmd.dvsRules && setting.FilterPolicy != nil && 202 setting.FilterPolicy.FilterConfig != nil && 203 len(setting.FilterPolicy.FilterConfig) > 0 { 204 205 rules, ok := setting.FilterPolicy.FilterConfig[0].(*types.DvsTrafficFilterConfig) 206 if !ok { 207 continue 208 } 209 if rules != nil && rules.TrafficRuleset != nil { 210 for _, rule := range rules.TrafficRuleset.Rules { 211 for _, q := range rule.Qualifier { 212 var protocol string 213 ipr, ok := q.(*types.DvsIpNetworkRuleQualifier) 214 if !ok { 215 continue 216 } 217 if val, ok := protocols[ipr.Protocol.Value]; ok { 218 protocol = val 219 } else { 220 protocol = fmt.Sprintf("%d", ipr.Protocol.Value) 221 } 222 223 trafficRuleSet[portID][int(rule.Sequence)] = trafficRule{ 224 Description: rule.Description, 225 Direction: rule.Direction, 226 Action: printAction(rule.Action), 227 Protocol: protocol, 228 SourceAddress: printAddress(ipr.SourceAddress), 229 SourceIpPort: printPort(ipr.SourceIpPort), 230 DestinationAddress: printAddress(ipr.DestinationAddress), 231 DestinationIpPort: printPort(ipr.DestinationIpPort), 232 } 233 } 234 } 235 } 236 } 237 } 238 } 239 240 if r.cmd.dvsRules && len(r.Port) > 0 { 241 eq := 0 242 for i := range r.Port { 243 if i > 0 { 244 reflect.DeepEqual(trafficRuleSet[i-1], trafficRuleSet[i]) 245 if reflect.DeepEqual(trafficRuleSet[i-1], trafficRuleSet[i]) { 246 eq++ 247 } else { 248 fmt.Printf("%s and %s port rules are unequal\n", r.Port[i-1].Key, r.Port[i].Key) 249 break 250 } 251 } 252 } 253 254 if eq == len(trafficRuleSet)-1 { 255 printTable(trafficRuleSet, 0) 256 } else { 257 for portID, port := range r.Port { 258 fmt.Printf("\nPortKey: %s\n", port.Key) 259 printTable(trafficRuleSet, portID) 260 } 261 } 262 } 263 264 return nil 265 } 266 267 func (cmd *info) Run(ctx context.Context, f *flag.FlagSet) error { 268 if f.NArg() != 1 { 269 return flag.ErrHelp 270 } 271 272 finder, err := cmd.Finder() 273 if err != nil { 274 return err 275 } 276 277 // Retrieve DVS reference 278 net, err := finder.Network(ctx, f.Arg(0)) 279 if err != nil { 280 return err 281 } 282 283 // Convert to DVS object type 284 dvs, ok := net.(*object.DistributedVirtualSwitch) 285 if !ok { 286 return fmt.Errorf("%s (%s) is not a DVS", f.Arg(0), net.Reference().Type) 287 } 288 289 // Set base search criteria 290 criteria := types.DistributedVirtualSwitchPortCriteria{ 291 Connected: types.NewBool(cmd.connected), 292 Active: types.NewBool(cmd.active), 293 UplinkPort: types.NewBool(cmd.uplinkPort), 294 Inside: types.NewBool(cmd.inside), 295 } 296 297 // If a distributed virtual portgroup path is set, then add its portgroup key to the base criteria 298 if len(cmd.pg) > 0 { 299 // Retrieve distributed virtual portgroup reference 300 net, err = finder.Network(ctx, cmd.pg) 301 if err != nil { 302 return err 303 } 304 305 // Convert distributed virtual portgroup object type 306 dvpg, ok := net.(*object.DistributedVirtualPortgroup) 307 if !ok { 308 return fmt.Errorf("%s (%s) is not a DVPG", cmd.pg, net.Reference().Type) 309 } 310 311 // Obtain portgroup key property 312 var dvp mo.DistributedVirtualPortgroup 313 if err := dvpg.Properties(ctx, dvpg.Reference(), []string{"key"}, &dvp); err != nil { 314 return err 315 } 316 317 // Add portgroup key to port search criteria 318 criteria.PortgroupKey = []string{dvp.Key} 319 } 320 321 res, err := dvs.FetchDVPorts(ctx, &criteria) 322 if err != nil { 323 return err 324 } 325 326 // Truncate output to -count if specified 327 if cmd.count > 0 && cmd.count < len(res) { 328 res = res[:cmd.count] 329 } 330 331 info := infoResult{ 332 cmd: cmd, 333 Port: res, 334 } 335 336 return cmd.WriteResult(&info) 337 }