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