github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/openflow13/group.go (about) 1 package openflow13 2 3 // This file has all group related defs 4 5 import ( 6 "encoding/binary" 7 8 "github.com/contiv/libOpenflow/common" 9 log "github.com/sirupsen/logrus" 10 ) 11 12 const ( 13 OFPG_MAX = 0xffffff00 /* Last usable group number. */ 14 /* Fake groups. */ 15 OFPG_ALL = 0xfffffffc /* Represents all groups for group delete commands. */ 16 OFPG_ANY = 0xffffffff /* Wildcard group used only for flow stats requests. Selects all flows regardless of group (including flows with no group). 17 */ 18 ) 19 20 const ( 21 OFPGC_ADD = 0 /* New group. */ 22 OFPGC_MODIFY = 1 /* Modify all matching groups. */ 23 OFPGC_DELETE = 2 /* Delete all matching groups. */ 24 OFPGC_INSERT_BUCKET = 3 /* Insert action buckets to the already available 25 list of action buckets in a matching group */ 26 ) 27 28 const ( 29 OFPGT_ALL = 0 /* All (multicast/broadcast) group. */ 30 OFPGT_SELECT = 1 /* Select group. */ 31 OFPGT_INDIRECT = 2 /* Indirect group. */ 32 OFPGT_FF = 3 /* Fast failover group. */ 33 ) 34 35 // GroupMod message 36 type GroupMod struct { 37 common.Header 38 Command uint16 /* One of OFPGC_*. */ 39 Type uint8 /* One of OFPGT_*. */ 40 pad uint8 /* Pad to 64 bits. */ 41 GroupId uint32 /* Group identifier. */ 42 Buckets []Bucket /* List of buckets */ 43 } 44 45 // Create a new group mode message 46 func NewGroupMod() *GroupMod { 47 g := new(GroupMod) 48 g.Header = NewOfp13Header() 49 g.Header.Type = Type_GroupMod 50 51 g.Command = OFPGC_ADD 52 g.Type = OFPGT_ALL 53 g.GroupId = 0 54 g.Buckets = make([]Bucket, 0) 55 return g 56 } 57 58 // Add a bucket to group mod 59 func (g *GroupMod) AddBucket(bkt Bucket) { 60 g.Buckets = append(g.Buckets, bkt) 61 } 62 63 func (g *GroupMod) Len() (n uint16) { 64 n = g.Header.Len() 65 n += 8 66 if g.Command == OFPGC_DELETE { 67 return 68 } 69 70 for _, b := range g.Buckets { 71 n += b.Len() 72 } 73 74 return 75 } 76 77 func (g *GroupMod) MarshalBinary() (data []byte, err error) { 78 g.Header.Length = g.Len() 79 data, err = g.Header.MarshalBinary() 80 81 bytes := make([]byte, 8) 82 n := 0 83 binary.BigEndian.PutUint16(bytes[n:], g.Command) 84 n += 2 85 bytes[n] = g.Type 86 n += 1 87 bytes[n] = g.pad 88 n += 1 89 binary.BigEndian.PutUint32(bytes[n:], g.GroupId) 90 n += 4 91 data = append(data, bytes...) 92 93 for _, bkt := range g.Buckets { 94 bytes, err = bkt.MarshalBinary() 95 data = append(data, bytes...) 96 log.Debugf("Groupmod bucket: %v", bytes) 97 } 98 99 log.Debugf("GroupMod(%d): %v", len(data), data) 100 101 return 102 } 103 104 func (g *GroupMod) UnmarshalBinary(data []byte) error { 105 n := 0 106 g.Header.UnmarshalBinary(data[n:]) 107 n += int(g.Header.Len()) 108 109 g.Command = binary.BigEndian.Uint16(data[n:]) 110 n += 2 111 g.Type = data[n] 112 n += 1 113 g.pad = data[n] 114 n += 1 115 g.GroupId = binary.BigEndian.Uint32(data[n:]) 116 n += 4 117 118 for n < int(g.Header.Length) { 119 bkt := new(Bucket) 120 bkt.UnmarshalBinary(data[n:]) 121 g.Buckets = append(g.Buckets, *bkt) 122 n += int(bkt.Len()) 123 } 124 125 return nil 126 } 127 128 type Bucket struct { 129 Length uint16 /* Length the bucket in bytes, including this header and any padding to make it 64-bit aligned. */ 130 Weight uint16 /* Relative weight of bucket. Only defined for select groups. */ 131 WatchPort uint32 /* Used for FRR groups */ 132 WatchGroup uint32 /* Used for FRR groups */ 133 pad []byte /* 4 bytes */ 134 Actions []Action /* zero or more actions */ 135 } 136 137 // Create a new Bucket 138 func NewBucket() *Bucket { 139 bkt := new(Bucket) 140 141 bkt.Weight = 0 142 bkt.pad = make([]byte, 4) 143 bkt.Actions = make([]Action, 0) 144 bkt.WatchPort = P_ANY 145 bkt.WatchGroup = OFPG_ANY 146 bkt.Length = bkt.Len() 147 148 return bkt 149 } 150 151 // Add an action to the bucket 152 func (b *Bucket) AddAction(act Action) { 153 b.Actions = append(b.Actions, act) 154 } 155 156 func (b *Bucket) Len() (n uint16) { 157 n = 16 158 159 for _, a := range b.Actions { 160 n += a.Len() 161 } 162 163 // Round it to closest multiple of 8 164 n = ((n + 7) / 8) * 8 165 return 166 } 167 168 func (b *Bucket) MarshalBinary() (data []byte, err error) { 169 bytes := make([]byte, 16) 170 n := 0 171 b.Length = b.Len() // Calculate length first 172 binary.BigEndian.PutUint16(bytes[n:], b.Length) 173 n += 2 174 binary.BigEndian.PutUint16(bytes[n:], b.Weight) 175 n += 2 176 binary.BigEndian.PutUint32(bytes[n:], b.WatchPort) 177 n += 4 178 binary.BigEndian.PutUint32(bytes[n:], b.WatchGroup) 179 n += 4 180 data = append(data, bytes...) 181 182 for _, a := range b.Actions { 183 bytes, err = a.MarshalBinary() 184 data = append(data, bytes...) 185 } 186 187 return 188 } 189 190 func (b *Bucket) UnmarshalBinary(data []byte) error { 191 n := 0 192 b.Length = binary.BigEndian.Uint16(data[n:]) 193 n += 2 194 b.Weight = binary.BigEndian.Uint16(data[n:]) 195 n += 2 196 b.WatchPort = binary.BigEndian.Uint32(data[n:]) 197 n += 4 198 b.WatchGroup = binary.BigEndian.Uint32(data[n:]) 199 n += 4 200 n += 4 // for padding 201 202 for n < int(b.Length) { 203 a, err := DecodeAction(data[n:]) 204 if err != nil { 205 return err 206 } 207 b.Actions = append(b.Actions, a) 208 n += int(a.Len()) 209 } 210 211 return nil 212 }