Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2022-present Open Networking Foundation |
| 3 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | * you may not use this file except in compliance with the License. |
| 5 | * You may obtain a copy of the License at |
| 6 | * |
| 7 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | * |
| 9 | * Unless required by applicable law or agreed to in writing, software |
| 10 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | * See the License for the specific language governing permissions and |
| 13 | * limitations under the License. |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 14 | */ |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 15 | |
| 16 | package application |
| 17 | |
| 18 | import ( |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 19 | "context" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 20 | "encoding/json" |
| 21 | "errors" |
| 22 | "net" |
| 23 | "reflect" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 24 | "strings" |
| 25 | "sync" |
| 26 | "time" |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 27 | common "voltha-go-controller/internal/pkg/types" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 28 | |
| 29 | "github.com/google/gopacket" |
| 30 | "github.com/google/gopacket/layers" |
| 31 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 32 | "voltha-go-controller/database" |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 33 | cntlr "voltha-go-controller/internal/pkg/controller" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 34 | "voltha-go-controller/internal/pkg/of" |
Tinoj Joseph | 1d10832 | 2022-07-13 10:07:39 +0530 | [diff] [blame] | 35 | "voltha-go-controller/log" |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 36 | ) |
| 37 | |
| 38 | const ( |
| 39 | // IgmpVersion0 constant (Default init value) |
| 40 | IgmpVersion0 uint8 = 0 |
| 41 | // IgmpVersion1 constant |
| 42 | IgmpVersion1 uint8 = 1 |
| 43 | // IgmpVersion2 constant |
| 44 | IgmpVersion2 uint8 = 2 |
| 45 | // IgmpVersion3 constant |
| 46 | IgmpVersion3 uint8 = 3 |
| 47 | // MinKeepAliveInterval constant |
| 48 | MinKeepAliveInterval uint32 = 10 |
| 49 | // MaxDiffKAIntervalResp constant |
| 50 | MaxDiffKAIntervalResp uint32 = 5 |
| 51 | // StaticGroup constant |
| 52 | StaticGroup string = "static" |
| 53 | // DynamicGroup constant |
| 54 | DynamicGroup string = "dynamic" |
| 55 | // StaticPort constant |
| 56 | StaticPort string = "static_port" |
| 57 | // DefaultIgmpProfID constant |
| 58 | DefaultIgmpProfID = "" |
| 59 | //GroupExpiryTime - group expiry time in minutes |
| 60 | GroupExpiryTime uint32 = 15 |
| 61 | ) |
| 62 | |
| 63 | const ( |
| 64 | // JoinUnsuccessful constant |
| 65 | JoinUnsuccessful string = "JOIN-UNSUCCESSFUL" |
| 66 | // JoinUnsuccessfulExceededIGMPChanel constant |
| 67 | JoinUnsuccessfulExceededIGMPChanel string = "Exceeded subscriber or PON port IGMP channels threshold" |
| 68 | // JoinUnsuccessfulAddFlowGroupFailed constant |
| 69 | JoinUnsuccessfulAddFlowGroupFailed string = "Failed to add flow or group for a channel" |
| 70 | // JoinUnsuccessfulGroupNotConfigured constant |
| 71 | JoinUnsuccessfulGroupNotConfigured string = "Join received from a subscriber on non-configured group" |
| 72 | // JoinUnsuccessfulVlanDisabled constant |
| 73 | JoinUnsuccessfulVlanDisabled string = "Vlan is disabled" |
| 74 | // JoinUnsuccessfulDescription constant |
| 75 | JoinUnsuccessfulDescription string = "igmp join unsuccessful" |
| 76 | // QueryExpired constant |
| 77 | QueryExpired string = "QUERY-EXPIRED" |
| 78 | // QueryExpiredGroupSpecific constant |
| 79 | QueryExpiredGroupSpecific string = "Group specific multicast query expired" |
| 80 | // QueryExpiredDescription constant |
| 81 | QueryExpiredDescription string = "igmp query expired" |
| 82 | ) |
| 83 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 84 | // McastConfig structure |
| 85 | type McastConfig struct { |
| 86 | OltSerialNum string |
| 87 | MvlanProfileID string |
| 88 | IgmpProfileID string |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 89 | Version string |
| 90 | // This map will help in updating the igds whenever there is a igmp profile id update |
| 91 | IgmpGroupDevices sync.Map `json:"-"` // Key is group id |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 92 | IgmpProxyIP net.IP |
| 93 | OperState OperInProgress |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | var ( |
| 97 | // NullIPAddr is null ip address var |
| 98 | NullIPAddr = net.ParseIP("0.0.0.0") |
Tinoj Joseph | cf161be | 2022-07-07 19:47:47 +0530 | [diff] [blame] | 99 | // AllSystemsMulticastGroupIP |
| 100 | AllSystemsMulticastGroupIP = net.ParseIP("224.0.0.1") |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 101 | // igmpSrcMac for the proxy |
| 102 | igmpSrcMac string |
| 103 | ) |
| 104 | |
| 105 | func init() { |
| 106 | RegisterPacketHandler(IGMP, ProcessIgmpPacket) |
| 107 | } |
| 108 | |
| 109 | // ProcessIgmpPacket : CallBack function registered with application to handle IGMP packetIn |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 110 | func ProcessIgmpPacket(cntx context.Context, device string, port string, pkt gopacket.Packet) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 111 | GetApplication().IgmpPacketInd(device, port, pkt) |
| 112 | } |
| 113 | |
| 114 | func ipv4ToUint(ip net.IP) uint32 { |
| 115 | result := uint32(0) |
| 116 | addr := ip.To4() |
| 117 | if addr == nil { |
| 118 | logger.Warnw(ctx, "Invalid Group Addr", log.Fields{"IP": ip}) |
| 119 | return 0 |
| 120 | } |
| 121 | result = result + uint32(addr[0])<<24 |
| 122 | result = result + uint32(addr[1])<<16 |
| 123 | result = result + uint32(addr[2])<<8 |
| 124 | result = result + uint32(addr[3]) |
| 125 | return result |
| 126 | } |
| 127 | |
| 128 | func getPodMacAddr() (string, error) { |
| 129 | ifas, err := net.Interfaces() |
| 130 | if err != nil { |
| 131 | return "", err |
| 132 | } |
| 133 | var ipv4Addr net.IP |
| 134 | for _, ifa := range ifas { |
| 135 | addrs, err := ifa.Addrs() |
| 136 | if err != nil { |
| 137 | return "", err |
| 138 | } |
| 139 | for _, addr := range addrs { |
| 140 | if ipv4Addr = addr.(*net.IPNet).IP.To4(); ipv4Addr != nil { |
| 141 | if ipv4Addr.IsGlobalUnicast() { |
| 142 | logger.Infow(ctx, "Igmp Static config", log.Fields{"MacAddr": ifa.HardwareAddr.String(), "ipAddr": ipv4Addr}) |
| 143 | return ifa.HardwareAddr.String(), nil |
| 144 | } |
| 145 | } |
| 146 | } |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 147 | } |
| 148 | return "", errors.New("MAC Address not found,Setting default") |
| 149 | } |
| 150 | |
| 151 | // IgmpUsEthLayer : Layers defined for upstream communication |
| 152 | // Ethernet layer for upstream communication |
| 153 | func IgmpUsEthLayer(mcip net.IP) *layers.Ethernet { |
| 154 | eth := &layers.Ethernet{} |
| 155 | // TODO: Set the source MAC properly and remove hardcoding |
| 156 | eth.SrcMAC, _ = net.ParseMAC(igmpSrcMac) |
| 157 | eth.DstMAC, _ = net.ParseMAC("01:00:5e:00:00:00") |
| 158 | eth.DstMAC[3] = mcip[1] & 0x7f |
| 159 | eth.DstMAC[4] = mcip[2] |
| 160 | eth.DstMAC[5] = mcip[3] |
| 161 | eth.EthernetType = layers.EthernetTypeDot1Q |
| 162 | return eth |
| 163 | } |
| 164 | |
| 165 | // IgmpUsDot1qLayer set US VLAN layer |
| 166 | func IgmpUsDot1qLayer(vlan of.VlanType, priority uint8) *layers.Dot1Q { |
| 167 | dot1q := &layers.Dot1Q{} |
| 168 | dot1q.Priority = priority |
| 169 | dot1q.DropEligible = false |
| 170 | dot1q.VLANIdentifier = uint16(vlan) |
| 171 | dot1q.Type = layers.EthernetTypeIPv4 |
| 172 | return dot1q |
| 173 | } |
| 174 | |
| 175 | // Igmpv2UsIpv4Layer : Set the IP layer for IGMPv2 |
| 176 | // TODO - Identify correct way of obtaining source IP |
| 177 | // This should be the configured IGMP proxy address which should be per OLT |
| 178 | // We should probably be able to have a single function for both |
| 179 | // upstream and downstream |
| 180 | func Igmpv2UsIpv4Layer(src net.IP, mcip net.IP) *layers.IPv4 { |
| 181 | ip := &layers.IPv4{} |
| 182 | ip.Version = 4 |
| 183 | ip.Protocol = layers.IPProtocolIGMP |
| 184 | ip.TTL = 1 |
| 185 | ip.SrcIP = src |
| 186 | ip.DstIP = mcip |
| 187 | return ip |
| 188 | } |
| 189 | |
| 190 | // Igmpv3UsIpv4Layer : Set the IP layer for IGMPv3 |
| 191 | // TODO - Identify correct way of obtaining source IP |
| 192 | // This should be the configured IGMP proxy address which should be per OLT |
| 193 | // We should probably be able to have a single function for both |
| 194 | // upstream and downstream |
| 195 | func Igmpv3UsIpv4Layer(src net.IP) *layers.IPv4 { |
| 196 | ip := &layers.IPv4{} |
| 197 | ip.Version = 4 |
| 198 | ip.Protocol = layers.IPProtocolIGMP |
| 199 | ip.TTL = 1 |
| 200 | ip.SrcIP = src |
| 201 | ip.DstIP = net.ParseIP("224.0.0.22") |
| 202 | return ip |
| 203 | } |
| 204 | |
| 205 | // IgmpDsEthLayer : Layers defined for downstream communication |
| 206 | // Ethernet layer for downstream communication |
| 207 | func IgmpDsEthLayer(mcip net.IP) *layers.Ethernet { |
| 208 | eth := &layers.Ethernet{} |
| 209 | // TODO: Set the source and dest MAC properly and remove hardcoding |
| 210 | eth.SrcMAC, _ = net.ParseMAC(igmpSrcMac) |
| 211 | eth.DstMAC, _ = net.ParseMAC("01:00:5e:00:00:00") |
| 212 | eth.DstMAC[3] = mcip[1] & 0x7f |
| 213 | eth.DstMAC[4] = mcip[2] |
| 214 | eth.DstMAC[5] = mcip[3] |
| 215 | eth.EthernetType = layers.EthernetTypeDot1Q |
| 216 | return eth |
| 217 | } |
| 218 | |
| 219 | // IgmpDsDot1qLayer set the DS VLAN layer |
| 220 | func IgmpDsDot1qLayer(vlan of.VlanType, priority uint8) *layers.Dot1Q { |
| 221 | dot1q := &layers.Dot1Q{} |
| 222 | dot1q.Priority = priority |
| 223 | dot1q.DropEligible = false |
| 224 | dot1q.VLANIdentifier = uint16(vlan) |
| 225 | dot1q.Type = layers.EthernetTypeIPv4 |
| 226 | return dot1q |
| 227 | } |
| 228 | |
| 229 | // IgmpDsIpv4Layer set the IP layer |
| 230 | func IgmpDsIpv4Layer(src net.IP, mcip net.IP) *layers.IPv4 { |
| 231 | ip := &layers.IPv4{} |
| 232 | ip.Version = 4 |
| 233 | ip.Protocol = layers.IPProtocolIGMP |
| 234 | ip.TTL = 1 |
| 235 | ip.SrcIP = src |
| 236 | if mcip.Equal(net.ParseIP("0.0.0.0")) { |
| 237 | mcip = net.ParseIP("224.0.0.1") |
| 238 | } |
| 239 | ip.DstIP = mcip |
| 240 | return ip |
| 241 | } |
| 242 | |
| 243 | // IgmpQueryv2Layer : IGMP Query Layer |
| 244 | func IgmpQueryv2Layer(mcip net.IP, resptime time.Duration) *layers.IGMPv1or2 { |
| 245 | igmp := &layers.IGMPv1or2{} |
| 246 | igmp.Type = layers.IGMPMembershipQuery |
| 247 | igmp.GroupAddress = mcip |
| 248 | igmp.MaxResponseTime = resptime |
| 249 | return igmp |
| 250 | } |
| 251 | |
| 252 | // IgmpQueryv3Layer : IGMP v3 Query Layer |
| 253 | func IgmpQueryv3Layer(mcip net.IP, resptime time.Duration) *layers.IGMP { |
| 254 | igmp := &layers.IGMP{} |
| 255 | igmp.Type = layers.IGMPMembershipQuery |
| 256 | igmp.GroupAddress = mcip |
| 257 | igmp.MaxResponseTime = resptime |
| 258 | return igmp |
| 259 | } |
| 260 | |
| 261 | // IgmpReportv2Layer : IGMP Layer |
| 262 | func IgmpReportv2Layer(mcip net.IP) *layers.IGMPv1or2 { |
| 263 | igmp := &layers.IGMPv1or2{} |
| 264 | igmp.Type = layers.IGMPMembershipReportV2 |
| 265 | igmp.GroupAddress = mcip |
| 266 | return igmp |
| 267 | } |
| 268 | |
| 269 | // IgmpLeavev2Layer : IGMP Leave Layer |
| 270 | func IgmpLeavev2Layer(mcip net.IP) *layers.IGMPv1or2 { |
| 271 | igmp := &layers.IGMPv1or2{} |
| 272 | igmp.Type = layers.IGMPLeaveGroup |
| 273 | igmp.GroupAddress = mcip |
| 274 | return igmp |
| 275 | } |
| 276 | |
| 277 | // IgmpReportv3Layer : IGMP v3 Report Layer |
| 278 | func IgmpReportv3Layer(mcip net.IP, incl bool, srclist []net.IP) *layers.IGMP { |
| 279 | // IGMP base |
| 280 | igmp := &layers.IGMP{} |
| 281 | igmp.Type = layers.IGMPMembershipReportV3 |
| 282 | igmp.NumberOfGroupRecords = 1 |
| 283 | |
| 284 | // IGMP Group |
| 285 | group := layers.IGMPv3GroupRecord{} |
| 286 | if incl { |
| 287 | group.Type = layers.IGMPIsIn |
| 288 | } else { |
| 289 | group.Type = layers.IGMPIsEx |
| 290 | } |
| 291 | group.MulticastAddress = mcip |
| 292 | group.NumberOfSources = uint16(len(srclist)) |
| 293 | group.SourceAddresses = srclist |
| 294 | igmp.GroupRecords = append(igmp.GroupRecords, group) |
| 295 | |
| 296 | return igmp |
| 297 | } |
| 298 | |
| 299 | // Igmpv2QueryPacket : IGMP Query in Downstream |
| 300 | func Igmpv2QueryPacket(mcip net.IP, vlan of.VlanType, selfip net.IP, pbit uint8, maxResp uint32) ([]byte, error) { |
| 301 | // Construct the layers that form the packet |
| 302 | eth := IgmpDsEthLayer(mcip) |
| 303 | dot1q := IgmpDsDot1qLayer(vlan, pbit) |
| 304 | ip := IgmpDsIpv4Layer(selfip, mcip) |
| 305 | igmp := IgmpQueryv2Layer(mcip, time.Duration(maxResp)*time.Second) |
| 306 | |
| 307 | // Now prepare the buffer into which the layers are to be serialized |
| 308 | buff := gopacket.NewSerializeBuffer() |
| 309 | opts := gopacket.SerializeOptions{ |
| 310 | FixLengths: true, |
| 311 | ComputeChecksums: true, |
| 312 | } |
| 313 | if err := gopacket.SerializeLayers(buff, opts, eth, dot1q, ip, igmp); err != nil { |
| 314 | logger.Error(ctx, "Error in serializing layers") |
| 315 | return nil, err |
| 316 | } |
| 317 | return buff.Bytes(), nil |
| 318 | } |
| 319 | |
| 320 | // Igmpv3QueryPacket : IGMPv3 Query in Downstream |
| 321 | func Igmpv3QueryPacket(mcip net.IP, vlan of.VlanType, selfip net.IP, pbit uint8, maxResp uint32) ([]byte, error) { |
| 322 | // Construct the layers that form the packet |
| 323 | eth := IgmpDsEthLayer(mcip) |
| 324 | dot1q := IgmpDsDot1qLayer(vlan, pbit) |
| 325 | ip := IgmpDsIpv4Layer(selfip, mcip) |
| 326 | igmp := IgmpQueryv3Layer(mcip, time.Duration(maxResp)*time.Second) |
| 327 | |
| 328 | // Now prepare the buffer into which the layers are to be serialized |
| 329 | buff := gopacket.NewSerializeBuffer() |
| 330 | opts := gopacket.SerializeOptions{ |
| 331 | FixLengths: true, |
| 332 | ComputeChecksums: true, |
| 333 | } |
| 334 | if err := gopacket.SerializeLayers(buff, opts, eth, dot1q, ip, igmp); err != nil { |
| 335 | logger.Error(ctx, "Error in serializing layers") |
| 336 | return nil, err |
| 337 | } |
| 338 | return buff.Bytes(), nil |
| 339 | } |
| 340 | |
| 341 | // IgmpReportv2Packet : Packet - IGMP v2 report in upstream |
| 342 | func IgmpReportv2Packet(mcip net.IP, vlan of.VlanType, priority uint8, selfip net.IP) ([]byte, error) { |
| 343 | // Construct the layers that form the packet |
| 344 | eth := IgmpUsEthLayer(mcip) |
| 345 | dot1q := IgmpUsDot1qLayer(vlan, priority) |
| 346 | ip := Igmpv2UsIpv4Layer(selfip, mcip) |
| 347 | igmp := IgmpReportv2Layer(mcip) |
| 348 | |
| 349 | // Now prepare the buffer into which the layers are to be serialized |
| 350 | buff := gopacket.NewSerializeBuffer() |
| 351 | opts := gopacket.SerializeOptions{ |
| 352 | FixLengths: true, |
| 353 | ComputeChecksums: true, |
| 354 | } |
| 355 | if err := gopacket.SerializeLayers(buff, opts, eth, dot1q, ip, igmp); err != nil { |
| 356 | logger.Error(ctx, "Error in serializing layers") |
| 357 | return nil, err |
| 358 | } |
| 359 | return buff.Bytes(), nil |
| 360 | } |
| 361 | |
| 362 | // Igmpv3ReportPacket : Packet - IGMP v3 report in upstream |
| 363 | func Igmpv3ReportPacket(mcip net.IP, vlan of.VlanType, priority uint8, selfip net.IP, incl bool, srclist []net.IP) ([]byte, error) { |
| 364 | // Construct the layers that form the packet |
| 365 | eth := IgmpUsEthLayer(net.ParseIP("224.0.0.22").To4()) |
| 366 | dot1q := IgmpUsDot1qLayer(vlan, priority) |
| 367 | ip := Igmpv3UsIpv4Layer(selfip) |
| 368 | igmp := IgmpReportv3Layer(mcip, incl, srclist) |
| 369 | |
| 370 | // Now prepare the buffer into which the layers are to be serialized |
| 371 | buff := gopacket.NewSerializeBuffer() |
| 372 | opts := gopacket.SerializeOptions{ |
| 373 | FixLengths: true, |
| 374 | ComputeChecksums: true, |
| 375 | } |
| 376 | if err := gopacket.SerializeLayers(buff, opts, eth, dot1q, ip, igmp); err != nil { |
| 377 | logger.Error(ctx, "Error in serializing layers") |
| 378 | return nil, err |
| 379 | } |
| 380 | return buff.Bytes(), nil |
| 381 | } |
| 382 | |
| 383 | // IgmpLeavePacket : Packet- IGMP Leave in upstream |
| 384 | func IgmpLeavePacket(mcip net.IP, vlan of.VlanType, priority uint8, selfip net.IP) ([]byte, error) { |
| 385 | // Construct the layers that form the packet |
| 386 | eth := IgmpUsEthLayer(mcip) |
| 387 | dot1q := IgmpUsDot1qLayer(vlan, priority) |
| 388 | ip := Igmpv2UsIpv4Layer(selfip, mcip) |
| 389 | igmp := IgmpLeavev2Layer(mcip) |
| 390 | |
| 391 | // Now prepare the buffer into which the layers are to be serialized |
| 392 | buff := gopacket.NewSerializeBuffer() |
| 393 | opts := gopacket.SerializeOptions{ |
| 394 | FixLengths: true, |
| 395 | ComputeChecksums: true, |
| 396 | } |
| 397 | if err := gopacket.SerializeLayers(buff, opts, eth, dot1q, ip, igmp); err != nil { |
| 398 | logger.Error(ctx, "Error in serializing layers") |
| 399 | return nil, err |
| 400 | } |
| 401 | return buff.Bytes(), nil |
| 402 | } |
| 403 | |
| 404 | // getVersion to get igmp version type |
| 405 | func getVersion(ver string) uint8 { |
| 406 | if ver == "2" || ver == "v2" { |
| 407 | return IgmpVersion2 |
| 408 | } |
| 409 | return IgmpVersion3 |
| 410 | } |
| 411 | |
| 412 | // IsIPPresent is Utility to check if an IP address is in a list |
| 413 | func IsIPPresent(i net.IP, ips []net.IP) bool { |
| 414 | for _, ip := range ips { |
| 415 | if i.Equal(ip) { |
| 416 | return true |
| 417 | } |
| 418 | } |
| 419 | return false |
| 420 | } |
| 421 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 422 | // AddToPendingPool - adds Igmp Device obj to pending pool |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 423 | func AddToPendingPool(cntx context.Context, device string, groupKey string) bool { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 424 | logger.Infow(ctx, "Add Device to IgmpGroup Pending Pool", log.Fields{"Device": device, "GroupKey": groupKey}) |
| 425 | if grp, ok := GetApplication().IgmpGroups.Load(groupKey); ok { |
| 426 | ig := grp.(*IgmpGroup) |
| 427 | ig.PendingPoolLock.Lock() |
| 428 | logger.Infow(ctx, "Adding Device to IgmpGroup Pending Pool", log.Fields{"Device": device, "GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr.String()}) |
| 429 | ig.PendingGroupForDevice[device] = time.Now().Add(time.Duration(GroupExpiryTime) * time.Minute) |
| 430 | ig.PendingPoolLock.Unlock() |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 431 | if err := ig.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 432 | logger.Errorw(ctx, "Igmp group Write to DB failed", log.Fields{"groupName": ig.GroupName}) |
| 433 | } |
| 434 | return true |
| 435 | } |
| 436 | return false |
| 437 | } |
| 438 | |
| 439 | /* |
| 440 | func checkIfForceGroupRemove(device string) bool { |
| 441 | if d := GetApplication().GetDevice(device); d != nil { |
| 442 | if d.State == cntlr.DeviceStateREBOOTED || d.State == cntlr.DeviceStateDOWN { |
| 443 | return true |
| 444 | } |
| 445 | } |
| 446 | return false |
| 447 | }*/ |
| 448 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 449 | // SendQueryExpiredEventGroupSpecific to send group specific query expired event. |
| 450 | func SendQueryExpiredEventGroupSpecific(portKey string, igd *IgmpGroupDevice, igc *IgmpGroupChannel) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 451 | logger.Info(ctx, "Processing-SendQueryExpiredEventGroupSpecific-Event") |
| 452 | va := GetApplication() |
| 453 | mvpName := va.GetMvlanProfileByTag(igd.Mvlan).Name |
| 454 | |
| 455 | sendEvent := func(key interface{}, value interface{}) bool { |
| 456 | if value.(*VoltService).IgmpEnabled && value.(*VoltService).MvlanProfileName == mvpName { |
| 457 | logger.Debugw(ctx, "sending-query-expired-group-specific-event", log.Fields{"EventType": QueryExpiredGroupSpecific, "ServiceName": value.(*VoltService).Name}) |
| 458 | } |
| 459 | return false |
| 460 | } |
| 461 | |
| 462 | // Fetching service name to send with query expired event. |
| 463 | vpvs, _ := va.VnetsByPort.Load(portKey) |
| 464 | if vpvs == nil { |
| 465 | logger.Errorw(ctx, "volt-port-vnet-is-nil", log.Fields{"vpvs": vpvs}) |
| 466 | return |
| 467 | } |
| 468 | |
| 469 | for _, vpv := range vpvs.([]*VoltPortVnet) { |
| 470 | vpv.services.Range(sendEvent) |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | // GetMcastServiceForSubAlarm to get mcast service name for subscriber alarm. |
| 475 | func GetMcastServiceForSubAlarm(uniPort *VoltPort, mvp *MvlanProfile) string { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 476 | var serviceName string |
| 477 | mvpName := mvp.Name |
| 478 | |
| 479 | va := GetApplication() |
| 480 | |
| 481 | sendAlm := func(key interface{}, value interface{}) bool { |
| 482 | if value.(*VoltService).IgmpEnabled && value.(*VoltService).MvlanProfileName == mvpName { |
| 483 | serviceName = value.(*VoltService).Name |
| 484 | } |
| 485 | return true |
| 486 | } |
| 487 | |
| 488 | // Fetching service name to send with active channels exceeded per subscriber alarm. |
| 489 | vpvs, _ := va.VnetsByPort.Load(uniPort.Name) |
| 490 | if vpvs == nil { |
| 491 | logger.Errorw(ctx, "volt-port-vnet-is-nil", log.Fields{"vpvs": vpvs}) |
| 492 | return serviceName |
| 493 | } |
| 494 | |
| 495 | for _, vpv := range vpvs.([]*VoltPortVnet) { |
| 496 | vpv.services.Range(sendAlm) |
| 497 | } |
| 498 | |
| 499 | return serviceName |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 500 | } |
| 501 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 502 | // RestoreIgmpGroupsFromDb to restore igmp groups from database |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 503 | func (va *VoltApplication) RestoreIgmpGroupsFromDb(cntx context.Context) { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 504 | groups, _ := db.GetIgmpGroups(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 505 | for _, group := range groups { |
| 506 | b, ok := group.Value.([]byte) |
| 507 | if !ok { |
| 508 | logger.Warn(ctx, "The value type is not []byte") |
| 509 | continue |
| 510 | } |
| 511 | var ig IgmpGroup |
| 512 | err := json.Unmarshal(b, &ig) |
| 513 | if err != nil { |
| 514 | logger.Warn(ctx, "Unmarshal of IGMP Group failed") |
| 515 | continue |
| 516 | } |
| 517 | ig.Devices = make(map[string]*IgmpGroupDevice) |
| 518 | |
| 519 | //For Upgrade Case |
| 520 | if len(ig.PendingGroupForDevice) == 0 { |
| 521 | ig.PendingGroupForDevice = make(map[string]time.Time) |
| 522 | } |
| 523 | logger.Infow(ctx, "Restoring Groups", log.Fields{"igGroupID": ig.GroupID, "igGroupName": ig.GroupName, "igMvlan": ig.Mvlan}) |
| 524 | grpKey := ig.getKey() |
| 525 | va.IgmpGroups.Store(grpKey, &ig) |
| 526 | // Just delete and lose the IGMP group with the same group Id |
| 527 | if _, err := va.GetIgmpGroupID(ig.GroupID); err != nil { |
| 528 | logger.Warnw(ctx, "GetIgmpGroupID Failed", log.Fields{"igGroupID": ig.GroupID, "Error": err}) |
| 529 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 530 | ig.RestoreDevices(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 531 | |
| 532 | if ig.NumDevicesActive() == 0 { |
| 533 | va.AddGroupToPendingPool(&ig) |
| 534 | } |
| 535 | logger.Infow(ctx, "Restored Groups", log.Fields{"igGroupID": ig.GroupID, "igGroupName": ig.GroupName, "igMvlan": ig.Mvlan}) |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | // AddIgmpGroup : When the first IGMP packet is received, the MVLAN profile is identified |
| 540 | // for the IGMP group and grp obj is obtained from the available pending pool of groups. |
| 541 | // If not, new group obj will be created based on available group IDs |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 542 | func (va *VoltApplication) AddIgmpGroup(cntx context.Context, mvpName string, gip net.IP, device string) *IgmpGroup { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 543 | var ig *IgmpGroup |
| 544 | if mvp, grpName := va.GetMvlanProfileForMcIP(mvpName, gip); mvp != nil { |
| 545 | if ig = va.GetGroupFromPendingPool(mvp.Mvlan, device); ig != nil { |
| 546 | logger.Infow(ctx, "Igmp Group obtained from global pending pool", log.Fields{"MvlanProfile": mvpName, "GroupID": ig.GroupID, "Device": device, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr.String()}) |
| 547 | oldKey := mvp.generateGroupKey(ig.GroupName, ig.GroupAddr.String()) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 548 | ig.IgmpGroupReInit(cntx, grpName, gip) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 549 | ig.IsGroupStatic = mvp.Groups[grpName].IsStatic |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 550 | ig.UpdateIgmpGroup(cntx, oldKey, ig.getKey()) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 551 | } else { |
| 552 | logger.Infow(ctx, "No Igmp Group available in global pending pool. Creating new Igmp Group", log.Fields{"MvlanProfile": mvpName, "Device": device, "GroupAddr": gip.String()}) |
| 553 | if ig = va.GetAvailIgmpGroupID(); ig == nil { |
| 554 | logger.Error(ctx, "Igmp Group Creation Failed: Group Id Unavailable") |
| 555 | return nil |
| 556 | } |
| 557 | ig.IgmpGroupInit(grpName, gip, mvp) |
| 558 | grpKey := ig.getKey() |
| 559 | va.IgmpGroups.Store(grpKey, ig) |
| 560 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 561 | if err := ig.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 562 | logger.Errorw(ctx, "Igmp group Write to DB failed", log.Fields{"groupName": ig.GroupName}) |
| 563 | } |
| 564 | return ig |
| 565 | } |
Tinoj Joseph | 1d10832 | 2022-07-13 10:07:39 +0530 | [diff] [blame] | 566 | logger.Errorw(ctx, "GetMvlan Pro failed", log.Fields{"Group": gip}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 567 | return nil |
| 568 | } |
| 569 | |
| 570 | // GetIgmpGroup helps search for the IGMP group from the list of |
| 571 | // active IGMP groups. For now, the assumption is that a group |
| 572 | // cannot belong to more than on MVLAN. If we change that definition, |
| 573 | // we have to take a relook at this implementation. The key will include |
| 574 | // both MVLAN and the group IP. |
| 575 | func (va *VoltApplication) GetIgmpGroup(mvlan of.VlanType, gip net.IP) *IgmpGroup { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 576 | profile, _ := va.MvlanProfilesByTag.Load(mvlan) |
| 577 | if profile == nil { |
| 578 | logger.Errorw(ctx, "Mvlan Profile not found for incoming packet. Dropping Request", log.Fields{"Mvlan": mvlan, "GroupAddr": gip.String()}) |
| 579 | return nil |
| 580 | } |
| 581 | mvp := profile.(*MvlanProfile) |
| 582 | _, gName := va.GetMvlanProfileForMcIP(mvp.Name, gip) |
| 583 | grpKey := mvp.generateGroupKey(gName, gip.String()) |
| 584 | logger.Debugw(ctx, "Get IGMP Group", log.Fields{"Group": grpKey}) |
| 585 | igIntf, ok := va.IgmpGroups.Load(grpKey) |
| 586 | if ok { |
| 587 | logger.Debugw(ctx, "Get IGMP Group Success", log.Fields{"Group": grpKey}) |
| 588 | ig := igIntf.(*IgmpGroup) |
| 589 | |
| 590 | //Case: Group was part of pending and Join came with same channel or different channel from same group |
| 591 | // (from same or different device) |
| 592 | // In that case, the same group will be allocated since the group is still part of va.IgmpGroups |
| 593 | // So, the groups needs to be removed from global pending pool |
| 594 | va.RemoveGroupDevicesFromPendingPool(ig) |
| 595 | return ig |
| 596 | } |
| 597 | return nil |
| 598 | } |
| 599 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 600 | // DelIgmpGroup : When the last subscriber leaves the IGMP group across all the devices |
| 601 | // the IGMP group is removed. |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 602 | func (va *VoltApplication) DelIgmpGroup(cntx context.Context, ig *IgmpGroup) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 603 | profile, found := GetApplication().MvlanProfilesByTag.Load(ig.Mvlan) |
| 604 | if found { |
| 605 | mvp := profile.(*MvlanProfile) |
| 606 | |
| 607 | grpKey := mvp.generateGroupKey(ig.GroupName, ig.GroupAddr.String()) |
| 608 | |
| 609 | if igIntf, ok := va.IgmpGroups.Load(grpKey); ok { |
| 610 | ig := igIntf.(*IgmpGroup) |
| 611 | ig.IgmpGroupLock.Lock() |
| 612 | if ig.NumDevicesAll() == 0 { |
| 613 | logger.Debugw(ctx, "Deleting IGMP Group", log.Fields{"Group": grpKey}) |
| 614 | va.PutIgmpGroupID(ig) |
| 615 | va.IgmpGroups.Delete(grpKey) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 616 | _ = db.DelIgmpGroup(cntx, grpKey) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 617 | } else { |
| 618 | logger.Infow(ctx, "Skipping IgmpGroup Device. Pending Igmp Group Devices present", log.Fields{"GroupID": ig.GroupID, "GroupName": ig.GroupName, "GroupAddr": ig.GroupAddr.String(), "PendingDevices": len(ig.Devices)}) |
| 619 | va.AddGroupToPendingPool(ig) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 620 | if err := ig.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 621 | logger.Errorw(ctx, "Igmp group Write to DB failed", log.Fields{"groupName": ig.GroupName}) |
| 622 | } |
| 623 | } |
| 624 | ig.IgmpGroupLock.Unlock() |
| 625 | } |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 626 | } |
| 627 | } |
| 628 | |
| 629 | // GetPonPortID Gets the PON port ID from uniPortID |
| 630 | func (va *VoltApplication) GetPonPortID(device, uniPortID string) uint32 { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 631 | isNNI := strings.Contains(uniPortID, "nni") |
| 632 | if isNNI || uniPortID == StaticPort { |
| 633 | logger.Debugw(ctx, "Cannot get pon port from UNI port", log.Fields{"port": uniPortID}) |
| 634 | return 0xFF |
| 635 | } |
| 636 | dIntf, ok := va.DevicesDisc.Load(device) |
| 637 | if !ok { |
| 638 | return 0xFF |
| 639 | } |
| 640 | d := dIntf.(*VoltDevice) |
| 641 | |
| 642 | uniPort := d.GetPort(uniPortID) |
| 643 | if uniPort == nil { |
| 644 | return 0xFF |
| 645 | } |
| 646 | return GetPonPortIDFromUNIPort(uniPort.ID) |
| 647 | } |
| 648 | |
| 649 | // AggActiveChannelsCountPerSub aggregates the active channel count for given uni port. |
| 650 | // It will iterate over all the groups and store the sum of active channels in VoltPort. |
| 651 | func (va *VoltApplication) AggActiveChannelsCountPerSub(device, uniPort string, port *VoltPort) { |
| 652 | var activeChannelCount uint32 |
| 653 | |
| 654 | collectActiveChannelCount := func(key interface{}, value interface{}) bool { |
| 655 | ig := value.(*IgmpGroup) |
| 656 | igd := ig.Devices[device] |
| 657 | if igd == nil { |
| 658 | return true |
| 659 | } |
| 660 | if portChannels, ok := igd.PortChannelMap.Load(uniPort); ok { |
| 661 | channelList := portChannels.([]net.IP) |
| 662 | activeChannelCount += uint32(len(channelList)) |
| 663 | } |
| 664 | return true |
| 665 | } |
| 666 | va.IgmpGroups.Range(collectActiveChannelCount) |
| 667 | |
| 668 | logger.Debugw(ctx, "AggrActiveChannelCount for Subscriber", |
| 669 | log.Fields{"UniPortID": uniPort, "count": activeChannelCount}) |
| 670 | |
| 671 | port.ActiveChannels = activeChannelCount |
| 672 | } |
| 673 | |
| 674 | // AggActiveChannelsCountForPonPort Aggregates the active channel count for given pon port. |
| 675 | // It will iterate over all the groups and store the sum of active channels in VoltDevice. |
| 676 | func (va *VoltApplication) AggActiveChannelsCountForPonPort(device string, ponPortID uint32, port *PonPortCfg) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 677 | var activeChannelCount uint32 |
| 678 | |
| 679 | collectActiveChannelCount := func(key interface{}, value interface{}) bool { |
| 680 | ig := value.(*IgmpGroup) |
| 681 | igd := ig.Devices[device] |
| 682 | if igd == nil { |
| 683 | return true |
| 684 | } |
| 685 | if ponPortChannels, ok := igd.PonPortChannelMap.Get(ponPortID); ok { |
| 686 | activeChannelCount += ponPortChannels.(*PonPortChannels).GetActiveChannelCount() |
| 687 | } |
| 688 | return true |
| 689 | } |
| 690 | va.IgmpGroups.Range(collectActiveChannelCount) |
| 691 | |
| 692 | logger.Debugw(ctx, "AggrActiveChannelCount for Pon Port", |
| 693 | log.Fields{"PonPortID": ponPortID, "count": activeChannelCount}) |
| 694 | |
| 695 | port.ActiveIGMPChannels = activeChannelCount |
| 696 | } |
| 697 | |
| 698 | // UpdateActiveChannelCountForPonPort increments the global counter for active |
| 699 | // channel count per pon port. |
| 700 | func (va *VoltApplication) UpdateActiveChannelCountForPonPort(device, uniPortID string, ponPortID uint32, isAdd, isChannel bool, igd *IgmpGroupDevice) { |
| 701 | incrDecr := func(value uint32) uint32 { |
| 702 | if isAdd { |
| 703 | return value + 1 |
| 704 | } |
| 705 | return value - 1 |
| 706 | } |
| 707 | if d, exists := va.DevicesDisc.Load(device); exists { |
| 708 | voltDevice := d.(*VoltDevice) |
| 709 | |
| 710 | if isChannel { |
| 711 | voltDevice.ActiveChannelCountLock.Lock() |
| 712 | // If New channel is added/deleted, then only update the ActiveChannelsPerPon |
| 713 | if value, ok := voltDevice.ActiveChannelsPerPon.Load(ponPortID); ok { |
| 714 | port := value.(*PonPortCfg) |
| 715 | port.ActiveIGMPChannels = incrDecr(port.ActiveIGMPChannels) |
| 716 | voltDevice.ActiveChannelsPerPon.Store(ponPortID, port) |
| 717 | logger.Debugw(ctx, "+++ActiveChannelsPerPon", log.Fields{"count": port.ActiveIGMPChannels}) // TODO: remove me |
| 718 | } |
| 719 | voltDevice.ActiveChannelCountLock.Unlock() |
| 720 | } |
| 721 | if uPort, ok := voltDevice.Ports.Load(uniPortID); ok { |
| 722 | uniPort := uPort.(*VoltPort) |
| 723 | uniPort.ActiveChannels = incrDecr(uniPort.ActiveChannels) |
| 724 | voltDevice.Ports.Store(uniPortID, uniPort) |
| 725 | logger.Debugw(ctx, "+++ActiveChannelsPerSub", log.Fields{"count": uniPort.ActiveChannels}) // TODO: remove me |
| 726 | } |
| 727 | } |
| 728 | } |
| 729 | |
| 730 | // IsMaxChannelsCountExceeded checks if the PON port active channel |
| 731 | // capacity and subscriber level channel capacity is reached to max allowed |
| 732 | // channel per pon threshold. If Exceeds, return true else return false. |
| 733 | func (va *VoltApplication) IsMaxChannelsCountExceeded(device, uniPortID string, |
| 734 | ponPortID uint32, ig *IgmpGroup, channelIP net.IP, mvp *MvlanProfile) bool { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 735 | // New receiver check is required to identify the IgmpReportMsg received |
| 736 | // in response to the IGMP Query sent from VGC. |
| 737 | if newReceiver := ig.IsNewReceiver(device, uniPortID, channelIP); !newReceiver { |
| 738 | logger.Debugw(ctx, "Not a new receiver. It is a response to IGMP Query", |
| 739 | log.Fields{"port": uniPortID, "channel": channelIP}) |
| 740 | return false |
| 741 | } |
| 742 | |
| 743 | if vDev, exists := va.DevicesDisc.Load(device); exists { |
| 744 | voltDevice := vDev.(*VoltDevice) |
| 745 | |
| 746 | // Checking subscriber active channel count with maxChannelsAllowedPerSub |
| 747 | if uniPort, present := voltDevice.Ports.Load(uniPortID); present { |
| 748 | if uniPort.(*VoltPort).ActiveChannels >= mvp.MaxActiveChannels { |
| 749 | logger.Errorw(ctx, "Max allowed channels per subscriber is exceeded", |
| 750 | log.Fields{"activeCount": uniPort.(*VoltPort).ActiveChannels, "channel": channelIP, "UNI": uniPort.(*VoltPort).Name}) |
| 751 | if !(uniPort.(*VoltPort).ChannelPerSubAlarmRaised) { |
| 752 | serviceName := GetMcastServiceForSubAlarm(uniPort.(*VoltPort), mvp) |
| 753 | logger.Debugw(ctx, "Raising-SendActiveChannelPerSubscriberAlarm-Initiated", log.Fields{"ActiveChannels": uniPort.(*VoltPort).ActiveChannels, "ServiceName": serviceName}) |
| 754 | uniPort.(*VoltPort).ChannelPerSubAlarmRaised = true |
| 755 | } |
| 756 | return true |
| 757 | } |
| 758 | } else { |
| 759 | logger.Errorw(ctx, "UNI port not found in VoltDevice", log.Fields{"uniPortID": uniPortID}) |
| 760 | } |
| 761 | if value, ok := voltDevice.ActiveChannelsPerPon.Load(ponPortID); ok { |
| 762 | ponPort := value.(*PonPortCfg) |
| 763 | |
| 764 | logger.Debugw(ctx, "----Active channels count for PON port", |
| 765 | log.Fields{"PonPortID": ponPortID, "activeChannels": ponPort.ActiveIGMPChannels, |
| 766 | "maxAllowedChannelsPerPon": ponPort.MaxActiveChannels}) |
| 767 | |
| 768 | if ponPort.ActiveIGMPChannels < ponPort.MaxActiveChannels { |
| 769 | // PON port active channel capacity is not yet reached to max allowed channels per pon. |
| 770 | // So allowing to add receiver. |
| 771 | return false |
| 772 | } else if ponPort.ActiveIGMPChannels >= ponPort.MaxActiveChannels && ig != nil { |
| 773 | // PON port active channel capacity is reached to max allowed channels per pon. |
| 774 | // Check if same channel is already configured on that PON port. |
| 775 | // If that channel is present, then allow AddReceiver else it will be rejected. |
| 776 | igd, isPresent := ig.Devices[device] |
| 777 | if isPresent { |
| 778 | if channelListForPonPort, _ := igd.PonPortChannelMap.Get(ponPortID); channelListForPonPort != nil { |
| 779 | if _, isExists := channelListForPonPort.(*PonPortChannels).ChannelList.Get(channelIP.String()); isExists { |
| 780 | return false |
| 781 | } |
| 782 | } |
| 783 | } |
| 784 | } |
| 785 | logger.Errorw(ctx, "Active channels count for PON port exceeded", |
| 786 | log.Fields{"PonPortID": ponPortID, "activeChannels": ponPort.ActiveIGMPChannels, "channel": channelIP, "UNI": uniPortID}) |
| 787 | } else { |
| 788 | logger.Warnw(ctx, "PON port level active channel count does not exists", |
| 789 | log.Fields{"ponPortID": ponPortID}) |
| 790 | return false |
| 791 | } |
| 792 | } |
| 793 | logger.Warnw(ctx, "Max allowed channels per pon threshold is reached", log.Fields{"PonPortID": ponPortID}) |
| 794 | return true |
| 795 | } |
| 796 | |
| 797 | // ProcessIgmpv2Pkt : This is IGMPv2 packet. |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 798 | func (va *VoltApplication) ProcessIgmpv2Pkt(cntx context.Context, device string, port string, pkt gopacket.Packet) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 799 | // First get the layers of interest |
| 800 | dot1Q := pkt.Layer(layers.LayerTypeDot1Q).(*layers.Dot1Q) |
| 801 | pktVlan := of.VlanType(dot1Q.VLANIdentifier) |
| 802 | igmpv2 := pkt.Layer(layers.LayerTypeIGMP).(*layers.IGMPv1or2) |
| 803 | |
| 804 | ponPortID := va.GetPonPortID(device, port) |
| 805 | |
| 806 | var vpv *VoltPortVnet |
| 807 | |
| 808 | logger.Debugw(ctx, "Received IGMPv2 Type", log.Fields{"Type": igmpv2.Type}) |
| 809 | |
| 810 | if igmpv2.Type == layers.IGMPMembershipReportV2 || igmpv2.Type == layers.IGMPMembershipReportV1 { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 811 | logger.Infow(ctx, "IGMP Join received: v2", log.Fields{"Addr": igmpv2.GroupAddress, "Port": port}) |
| 812 | |
| 813 | // This is a report coming from the PON. We must be able to first find the |
| 814 | // subscriber from the VLAN tag and port and verify if the IGMP proxy is |
| 815 | // enabled for the subscriber |
| 816 | vpv, _ = va.GetVnetFromPkt(device, port, pkt) |
| 817 | |
| 818 | if vpv == nil { |
| 819 | logger.Errorw(ctx, "Couldn't find VNET associated with port", log.Fields{"Port": port}) |
| 820 | return |
| 821 | } else if !vpv.IgmpEnabled { |
| 822 | logger.Errorw(ctx, "IGMP is not activated on the port", log.Fields{"Port": port}) |
| 823 | return |
| 824 | } |
| 825 | |
| 826 | mvp := va.GetMvlanProfileByName(vpv.MvlanProfileName) |
| 827 | if mvp == nil { |
| 828 | logger.Errorw(ctx, "Igmp Packet Received for Subscriber with Missing Mvlan Profile", |
| 829 | log.Fields{"Receiver": vpv.Port, "MvlanProfile": vpv.MvlanProfileName}) |
| 830 | return |
| 831 | } |
| 832 | mvlan := mvp.Mvlan |
| 833 | |
| 834 | mvp.mvpLock.RLock() |
| 835 | defer mvp.mvpLock.RUnlock() |
| 836 | // The subscriber is validated and now process the IGMP report |
| 837 | ig := va.GetIgmpGroup(mvlan, igmpv2.GroupAddress) |
| 838 | |
| 839 | if yes := va.IsMaxChannelsCountExceeded(device, port, ponPortID, ig, igmpv2.GroupAddress, mvp); yes { |
| 840 | logger.Warnw(ctx, "Dropping IGMP Join v2: Active channel threshold exceeded", |
| 841 | log.Fields{"PonPortID": ponPortID, "Addr": igmpv2.GroupAddress, "MvlanProfile": vpv.MvlanProfileName}) |
| 842 | return |
| 843 | } |
| 844 | if ig != nil { |
| 845 | logger.Infow(ctx, "IGMP Group", log.Fields{"Group": ig.GroupID, "devices": ig.Devices}) |
| 846 | // If the IGMP group is already created. just add the receiver |
| 847 | ig.IgmpGroupLock.Lock() |
| 848 | // Check for port state to avoid race condition where PortDown event |
| 849 | // acquired lock before packet processing |
| 850 | vd := GetApplication().GetDevice(device) |
| 851 | vp := vd.GetPort(port) |
| 852 | if vp == nil || vp.State != PortStateUp { |
| 853 | logger.Warnw(ctx, "Join received from a Port that is DOWN or not present", |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 854 | log.Fields{"Port": port}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 855 | ig.IgmpGroupLock.Unlock() |
| 856 | return |
| 857 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 858 | ig.AddReceiver(cntx, device, port, igmpv2.GroupAddress, nil, IgmpVersion2, dot1Q.VLANIdentifier, dot1Q.Priority, ponPortID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 859 | ig.IgmpGroupLock.Unlock() |
| 860 | } else { |
| 861 | // Create the IGMP group and then add the receiver to the group |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 862 | if ig := va.AddIgmpGroup(cntx, vpv.MvlanProfileName, igmpv2.GroupAddress, device); ig != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 863 | logger.Infow(ctx, "New IGMP Group", log.Fields{"Group": ig.GroupID, "devices": ig.Devices}) |
| 864 | ig.IgmpGroupLock.Lock() |
| 865 | // Check for port state to avoid race condition where PortDown event |
| 866 | // acquired lock before packet processing |
| 867 | vd := GetApplication().GetDevice(device) |
| 868 | vp := vd.GetPort(port) |
| 869 | if vp == nil || vp.State != PortStateUp { |
| 870 | logger.Warnw(ctx, "Join received from a Port that is DOWN or not present", |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 871 | log.Fields{"Port": port}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 872 | ig.IgmpGroupLock.Unlock() |
| 873 | return |
| 874 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 875 | ig.AddReceiver(cntx, device, port, igmpv2.GroupAddress, nil, IgmpVersion2, dot1Q.VLANIdentifier, dot1Q.Priority, ponPortID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 876 | ig.IgmpGroupLock.Unlock() |
| 877 | } else { |
| 878 | logger.Errorw(ctx, "IGMP Group Creation Failed", log.Fields{"Addr": igmpv2.GroupAddress}) |
| 879 | return |
| 880 | } |
| 881 | } |
| 882 | } else if igmpv2.Type == layers.IGMPLeaveGroup { |
| 883 | // This is a IGMP leave coming from one of the receivers. We essentially remove the |
| 884 | // the receiver. |
| 885 | logger.Infow(ctx, "IGMP Leave received: v2", log.Fields{"Addr": igmpv2.GroupAddress, "Port": port}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 886 | vpv, _ = va.GetVnetFromPkt(device, port, pkt) |
| 887 | if vpv == nil { |
| 888 | logger.Errorw(ctx, "Couldn't find VNET associated with port", log.Fields{"Port": port}) |
| 889 | return |
| 890 | } else if !vpv.IgmpEnabled { |
| 891 | logger.Errorw(ctx, "IGMP is not activated on the port", log.Fields{"Port": port}) |
| 892 | return |
| 893 | } |
| 894 | |
| 895 | mvp := va.GetMvlanProfileByName(vpv.MvlanProfileName) |
| 896 | mvp.mvpLock.RLock() |
| 897 | defer mvp.mvpLock.RUnlock() |
| 898 | mvlan := mvp.Mvlan |
| 899 | // The subscriber is validated and now process the IGMP report |
| 900 | if ig := va.GetIgmpGroup(mvlan, igmpv2.GroupAddress); ig != nil { |
| 901 | ig.IgmpGroupLock.Lock() |
| 902 | // Delete the receiver once the IgmpGroup is identified |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 903 | ig.DelReceiver(cntx, device, port, igmpv2.GroupAddress, nil, ponPortID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 904 | ig.IgmpGroupLock.Unlock() |
| 905 | if ig.NumDevicesActive() == 0 { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 906 | va.DelIgmpGroup(cntx, ig) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 907 | } |
| 908 | } |
| 909 | } else { |
| 910 | // This must be a query on the NNI port. However, we dont make that assumption. |
| 911 | // Need to look for the IGMP group based on the VLAN in the packet as |
| 912 | // the MVLAN |
| 913 | |
| 914 | //Check if mvlan profile exist for the incoming pkt vlan |
| 915 | profile, _ := va.MvlanProfilesByTag.Load(pktVlan) |
| 916 | if profile == nil { |
| 917 | logger.Errorw(ctx, "Mvlan Profile not found for incoming packet. Dropping Request", log.Fields{"Mvlan": pktVlan}) |
| 918 | return |
| 919 | } |
| 920 | mvp := profile.(*MvlanProfile) |
| 921 | mvp.mvpLock.RLock() |
| 922 | defer mvp.mvpLock.RUnlock() |
| 923 | |
| 924 | if net.ParseIP("0.0.0.0").Equal(igmpv2.GroupAddress) { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 925 | va.processIgmpQueries(cntx, device, pktVlan, IgmpVersion2) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 926 | } else { |
| 927 | if ig := va.GetIgmpGroup(pktVlan, igmpv2.GroupAddress); ig != nil { |
| 928 | ig.IgmpGroupLock.Lock() |
| 929 | igd, ok := ig.Devices[device] |
| 930 | if ok { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 931 | igd.ProcessQuery(cntx, igmpv2.GroupAddress, IgmpVersion2) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 932 | } else { |
| 933 | logger.Warnw(ctx, "IGMP Device not found", log.Fields{"Device": device, "Group": igmpv2.GroupAddress}) |
| 934 | } |
| 935 | ig.IgmpGroupLock.Unlock() |
| 936 | } |
| 937 | } |
| 938 | } |
| 939 | } |
| 940 | |
| 941 | // ProcessIgmpv3Pkt : Process IGMPv3 packet |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 942 | func (va *VoltApplication) ProcessIgmpv3Pkt(cntx context.Context, device string, port string, pkt gopacket.Packet) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 943 | // First get the layers of interest |
| 944 | dot1QLayer := pkt.Layer(layers.LayerTypeDot1Q) |
| 945 | |
| 946 | if dot1QLayer == nil { |
| 947 | logger.Error(ctx, "Igmp Packet Received without Vlan - Dropping pkt") |
| 948 | return |
| 949 | } |
| 950 | dot1Q := dot1QLayer.(*layers.Dot1Q) |
| 951 | pktVlan := of.VlanType(dot1Q.VLANIdentifier) |
| 952 | igmpv3 := pkt.Layer(layers.LayerTypeIGMP).(*layers.IGMP) |
| 953 | |
| 954 | ponPortID := va.GetPonPortID(device, port) |
| 955 | |
| 956 | var vpv *VoltPortVnet |
| 957 | logger.Debugw(ctx, "Received IGMPv3 Type", log.Fields{"Type": igmpv3.Type}) |
| 958 | |
| 959 | if igmpv3.Type == layers.IGMPMembershipReportV3 { |
| 960 | // This is a report coming from the PON. We must be able to first find the |
| 961 | // subscriber from the VLAN tag and port and verify if the IGMP proxy is |
| 962 | // enabled for the subscriber |
| 963 | vpv, _ = va.GetVnetFromPkt(device, port, pkt) |
| 964 | if vpv == nil { |
| 965 | logger.Errorw(ctx, "Couldn't find VNET associated with port", log.Fields{"Port": port}) |
| 966 | return |
| 967 | } else if !vpv.IgmpEnabled { |
| 968 | logger.Errorw(ctx, "IGMP is not activated on the port", log.Fields{"Port": port}) |
| 969 | return |
| 970 | } |
| 971 | mvp := va.GetMvlanProfileByName(vpv.MvlanProfileName) |
| 972 | if mvp == nil { |
| 973 | logger.Errorw(ctx, "Igmp Packet received for Subscriber with Missing Mvlan Profile", |
| 974 | log.Fields{"Receiver": vpv.Port, "MvlanProfile": vpv.MvlanProfileName}) |
| 975 | return |
| 976 | } |
| 977 | mvp.mvpLock.RLock() |
| 978 | defer mvp.mvpLock.RUnlock() |
| 979 | mvlan := mvp.Mvlan |
| 980 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 981 | for i, group := range igmpv3.GroupRecords { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 982 | isJoin := isIgmpJoin(group.Type, group.SourceAddresses) |
| 983 | // The subscriber is validated and now process the IGMP report |
| 984 | ig := va.GetIgmpGroup(mvlan, group.MulticastAddress) |
| 985 | if isJoin { |
| 986 | if yes := va.IsMaxChannelsCountExceeded(device, port, ponPortID, ig, group.MulticastAddress, mvp); yes { |
| 987 | logger.Warnw(ctx, "Dropping IGMP Join v3: Active channel threshold exceeded", |
| 988 | log.Fields{"PonPortID": ponPortID, "Addr": group.MulticastAddress, "MvlanProfile": vpv.MvlanProfileName}) |
| 989 | |
| 990 | return |
| 991 | } |
| 992 | if ig != nil { |
| 993 | // If the IGMP group is already created. just add the receiver |
| 994 | logger.Infow(ctx, "IGMP Join received for existing group", log.Fields{"Addr": group.MulticastAddress, "Port": port}) |
| 995 | ig.IgmpGroupLock.Lock() |
| 996 | // Check for port state to avoid race condition where PortDown event |
| 997 | // acquired lock before packet processing |
| 998 | vd := GetApplication().GetDevice(device) |
| 999 | vp := vd.GetPort(port) |
| 1000 | if vp == nil || vp.State != PortStateUp { |
| 1001 | logger.Warnw(ctx, "Join received from a Port that is DOWN or not present", |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1002 | log.Fields{"Port": port}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1003 | ig.IgmpGroupLock.Unlock() |
| 1004 | return |
| 1005 | } |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1006 | ig.AddReceiver(cntx, device, port, group.MulticastAddress, &igmpv3.GroupRecords[i], IgmpVersion3, |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1007 | dot1Q.VLANIdentifier, dot1Q.Priority, ponPortID) |
| 1008 | ig.IgmpGroupLock.Unlock() |
| 1009 | } else { |
| 1010 | // Create the IGMP group and then add the receiver to the group |
| 1011 | logger.Infow(ctx, "IGMP Join received for new group", log.Fields{"Addr": group.MulticastAddress, "Port": port}) |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1012 | if ig = va.AddIgmpGroup(cntx, vpv.MvlanProfileName, group.MulticastAddress, device); ig != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1013 | ig.IgmpGroupLock.Lock() |
| 1014 | // Check for port state to avoid race condition where PortDown event |
| 1015 | // acquired lock before packet processing |
| 1016 | vd := GetApplication().GetDevice(device) |
| 1017 | vp := vd.GetPort(port) |
| 1018 | if vp == nil || vp.State != PortStateUp { |
| 1019 | logger.Warnw(ctx, "Join received from a Port that is DOWN or not present", |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1020 | log.Fields{"Port": port}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1021 | ig.IgmpGroupLock.Unlock() |
| 1022 | return |
| 1023 | } |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1024 | ig.AddReceiver(cntx, device, port, group.MulticastAddress, &igmpv3.GroupRecords[i], IgmpVersion3, |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1025 | dot1Q.VLANIdentifier, dot1Q.Priority, ponPortID) |
| 1026 | ig.IgmpGroupLock.Unlock() |
| 1027 | } else { |
| 1028 | logger.Warnw(ctx, "IGMP Group Creation Failed", log.Fields{"Addr": group.MulticastAddress}) |
| 1029 | } |
| 1030 | } |
| 1031 | } else if ig != nil { |
| 1032 | logger.Infow(ctx, "IGMP Leave received for existing group", log.Fields{"Addr": group.MulticastAddress, "Port": port}) |
| 1033 | ig.IgmpGroupLock.Lock() |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1034 | ig.DelReceiver(cntx, device, port, group.MulticastAddress, &igmpv3.GroupRecords[i], ponPortID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1035 | ig.IgmpGroupLock.Unlock() |
| 1036 | if ig.NumDevicesActive() == 0 { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1037 | va.DelIgmpGroup(cntx, ig) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1038 | } |
| 1039 | } else { |
| 1040 | logger.Warnw(ctx, "IGMP Leave received for unknown group", log.Fields{"Addr": group.MulticastAddress}) |
| 1041 | } |
| 1042 | } |
| 1043 | } else { |
| 1044 | // This must be a query on the NNI port. However, we dont make that assumption. |
| 1045 | // Need to look for the IGMP group based on the VLAN in the packet as |
| 1046 | // the MVLAN |
| 1047 | |
| 1048 | //Check if mvlan profile exist for the incoming pkt vlan |
| 1049 | profile, _ := va.MvlanProfilesByTag.Load(pktVlan) |
| 1050 | if profile == nil { |
| 1051 | logger.Errorw(ctx, "Mvlan Profile not found for incoming packet. Dropping Request", log.Fields{"Mvlan": pktVlan}) |
| 1052 | return |
| 1053 | } |
| 1054 | mvp := profile.(*MvlanProfile) |
| 1055 | mvp.mvpLock.RLock() |
| 1056 | defer mvp.mvpLock.RUnlock() |
| 1057 | |
| 1058 | if net.ParseIP("0.0.0.0").Equal(igmpv3.GroupAddress) { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1059 | va.processIgmpQueries(cntx, device, pktVlan, IgmpVersion3) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1060 | } else { |
| 1061 | if ig := va.GetIgmpGroup(pktVlan, igmpv3.GroupAddress); ig != nil { |
| 1062 | ig.IgmpGroupLock.Lock() |
| 1063 | igd, ok := ig.Devices[device] |
| 1064 | if ok { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1065 | igd.ProcessQuery(cntx, igmpv3.GroupAddress, IgmpVersion3) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1066 | } else { |
| 1067 | logger.Warnw(ctx, "IGMP Device not found", log.Fields{"Device": device, "Group": igmpv3.GroupAddress}) |
| 1068 | } |
| 1069 | ig.IgmpGroupLock.Unlock() |
| 1070 | } |
| 1071 | } |
| 1072 | } |
| 1073 | } |
| 1074 | |
| 1075 | // processIgmpQueries to process the igmp queries |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1076 | func (va *VoltApplication) processIgmpQueries(cntx context.Context, device string, pktVlan of.VlanType, version uint8) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1077 | // This is a generic query and respond with all the groups channels in currently being viewed. |
| 1078 | processquery := func(key interface{}, value interface{}) bool { |
| 1079 | ig := value.(*IgmpGroup) |
| 1080 | ig.IgmpGroupLock.Lock() |
| 1081 | if ig.Mvlan != pktVlan { |
| 1082 | ig.IgmpGroupLock.Unlock() |
| 1083 | return true |
| 1084 | } |
| 1085 | igd, ok := ig.Devices[device] |
| 1086 | if !ok { |
| 1087 | logger.Warnw(ctx, "IGMP Device not found", log.Fields{"Device": device}) |
| 1088 | ig.IgmpGroupLock.Unlock() |
| 1089 | return true |
| 1090 | } |
| 1091 | processQueryForEachChannel := func(key interface{}, value interface{}) bool { |
| 1092 | groupAddr := key.(string) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1093 | igd.ProcessQuery(cntx, net.ParseIP(groupAddr), version) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1094 | return true |
| 1095 | } |
| 1096 | igd.GroupChannels.Range(processQueryForEachChannel) |
| 1097 | ig.IgmpGroupLock.Unlock() |
| 1098 | return true |
| 1099 | } |
| 1100 | va.IgmpGroups.Range(processquery) |
| 1101 | } |
| 1102 | |
| 1103 | // isIgmpJoin to check if it is igmp join |
| 1104 | func isIgmpJoin(recordType layers.IGMPv3GroupRecordType, sourceAddr []net.IP) bool { |
| 1105 | var join = false |
| 1106 | |
| 1107 | if (layers.IGMPToEx == recordType) || (layers.IGMPIsEx == recordType) { |
| 1108 | join = true |
| 1109 | } else if layers.IGMPBlock == recordType { |
| 1110 | if len(sourceAddr) == 0 { |
| 1111 | join = true |
| 1112 | } |
| 1113 | } else if (layers.IGMPToIn == recordType) || (layers.IGMPIsIn == recordType) || (layers.IGMPAllow == recordType) { |
| 1114 | if len(sourceAddr) != 0 { |
| 1115 | join = true |
| 1116 | } |
| 1117 | } |
| 1118 | return join |
| 1119 | } |
| 1120 | |
| 1121 | func isIncl(recordType layers.IGMPv3GroupRecordType) bool { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1122 | if (layers.IGMPToIn == recordType) || (layers.IGMPIsIn == recordType) || (layers.IGMPAllow == recordType) { |
| 1123 | return true |
| 1124 | } |
| 1125 | return false |
| 1126 | } |
| 1127 | |
| 1128 | // IgmpProcessPkt to process the IGMP packet received. The packet received brings along with it |
| 1129 | // the port on which the packet is received and the device the port is in. |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1130 | func (va *VoltApplication) IgmpProcessPkt(cntx context.Context, device string, port string, pkt gopacket.Packet) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1131 | igmpl := pkt.Layer(layers.LayerTypeIGMP) |
| 1132 | if igmpl == nil { |
| 1133 | logger.Error(ctx, "Invalid IGMP packet arrived as IGMP packet") |
| 1134 | return |
| 1135 | } |
| 1136 | if igmp, ok := igmpl.(*layers.IGMPv1or2); ok { |
| 1137 | // This is an IGMPv2 packet. |
| 1138 | logger.Debugw(ctx, "IGMPv2 Packet Received", log.Fields{"IPAddr": igmp.GroupAddress}) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1139 | va.ProcessIgmpv2Pkt(cntx, device, port, pkt) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1140 | return |
| 1141 | } |
| 1142 | if igmpv3, ok := igmpl.(*layers.IGMP); ok { |
| 1143 | logger.Debugw(ctx, "IGMPv3 Packet Received", log.Fields{"NumOfGroups": igmpv3.NumberOfGroupRecords}) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1144 | va.ProcessIgmpv3Pkt(cntx, device, port, pkt) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1145 | } |
| 1146 | } |
| 1147 | |
| 1148 | // IgmpPacketInd for igmp packet indication |
| 1149 | func (va *VoltApplication) IgmpPacketInd(device string, port string, pkt gopacket.Packet) { |
| 1150 | pt := NewIgmpPacketTask(device, port, pkt) |
| 1151 | va.IgmpTasks.AddTask(pt) |
| 1152 | } |
| 1153 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1154 | // storeMvlansMap to store mvlan map |
| 1155 | func (va *VoltApplication) storeMvlansMap(mvlan of.VlanType, name string, mvp *MvlanProfile) { |
| 1156 | va.MvlanProfilesByTag.Store(mvlan, mvp) |
| 1157 | va.MvlanProfilesByName.Store(name, mvp) |
| 1158 | } |
| 1159 | |
| 1160 | // deleteMvlansMap to delete mvlan map |
| 1161 | func (va *VoltApplication) deleteMvlansMap(mvlan of.VlanType, name string) { |
| 1162 | va.MvlanProfilesByTag.Delete(mvlan) |
| 1163 | va.MvlanProfilesByName.Delete(name) |
| 1164 | } |
| 1165 | |
| 1166 | // RestoreMvlansFromDb to read from the DB and restore all the MVLANs |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1167 | func (va *VoltApplication) RestoreMvlansFromDb(cntx context.Context) { |
| 1168 | mvlans, _ := db.GetMvlans(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1169 | for _, mvlan := range mvlans { |
| 1170 | b, ok := mvlan.Value.([]byte) |
| 1171 | if !ok { |
| 1172 | logger.Warn(ctx, "The value type is not []byte") |
| 1173 | continue |
| 1174 | } |
| 1175 | var mvp MvlanProfile |
| 1176 | err := json.Unmarshal(b, &mvp) |
| 1177 | if err != nil { |
| 1178 | logger.Warn(ctx, "Unmarshal of MVLAN failed") |
| 1179 | continue |
| 1180 | } |
| 1181 | va.storeMvlansMap(mvp.Mvlan, mvp.Name, &mvp) |
| 1182 | |
| 1183 | for srNo := range mvp.DevicesList { |
| 1184 | if mvp.IgmpServVersion[srNo] == nil { |
| 1185 | servVersion := IgmpVersion0 |
| 1186 | mvp.IgmpServVersion[srNo] = &servVersion |
| 1187 | } |
| 1188 | } |
| 1189 | logger.Infow(ctx, "Restored Mvlan Profile", log.Fields{"MVPName": mvp.Name}) |
| 1190 | } |
| 1191 | } |
| 1192 | |
| 1193 | // GetMvlanProfileByTag fetches MVLAN profile based on the MC VLAN |
| 1194 | func (va *VoltApplication) GetMvlanProfileByTag(vlan of.VlanType) *MvlanProfile { |
| 1195 | if mvp, ok := va.MvlanProfilesByTag.Load(vlan); ok { |
| 1196 | return mvp.(*MvlanProfile) |
| 1197 | } |
| 1198 | return nil |
| 1199 | } |
| 1200 | |
| 1201 | // GetMvlanProfileByName fetches MVLAN profile based on the profile name. |
| 1202 | func (va *VoltApplication) GetMvlanProfileByName(name string) *MvlanProfile { |
| 1203 | if mvp, ok := va.MvlanProfilesByName.Load(name); ok { |
| 1204 | return mvp.(*MvlanProfile) |
| 1205 | } |
| 1206 | return nil |
| 1207 | } |
| 1208 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1209 | // UpdateMvlanProfile - only channel groups be updated |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1210 | func (va *VoltApplication) UpdateMvlanProfile(cntx context.Context, name string, vlan of.VlanType, groups map[string][]string, activeChannelCount int, proxy map[string]common.MulticastGroupProxy) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1211 | mvpIntf, ok := va.MvlanProfilesByName.Load(name) |
| 1212 | if !ok { |
| 1213 | logger.Error(ctx, "Update Mvlan Failed: Profile does not exist") |
| 1214 | return errors.New("MVLAN profile not found") |
| 1215 | } |
| 1216 | mvp := mvpIntf.(*MvlanProfile) |
| 1217 | // check if groups are same then just update the OLTSerial numbers, push the config on new serial numbers |
| 1218 | |
| 1219 | existingGroup := mvp.Groups |
| 1220 | existingProxy := mvp.Proxy |
| 1221 | mvp.Groups = make(map[string]*MvlanGroup) |
| 1222 | mvp.Proxy = make(map[string]*MCGroupProxy) |
| 1223 | |
| 1224 | /* Need to protect groups and proxy write lock */ |
| 1225 | mvp.mvpLock.Lock() |
| 1226 | for grpName, grpIPList := range groups { |
| 1227 | mvp.AddMvlanGroup(grpName, grpIPList) |
| 1228 | } |
| 1229 | for grpName, proxyInfo := range proxy { |
| 1230 | mvp.AddMvlanProxy(grpName, proxyInfo) |
| 1231 | } |
| 1232 | if _, ok := mvp.Groups[common.StaticGroup]; ok { |
| 1233 | if _, yes := mvp.Proxy[common.StaticGroup]; !yes { |
| 1234 | mvp.Groups[common.StaticGroup].IsStatic = true |
| 1235 | } |
| 1236 | } |
| 1237 | prevMaxActiveChannels := mvp.MaxActiveChannels |
| 1238 | if reflect.DeepEqual(mvp.Groups, existingGroup) && reflect.DeepEqual(mvp.Proxy, existingProxy) { |
| 1239 | logger.Info(ctx, "No change in groups config") |
| 1240 | if uint32(activeChannelCount) != mvp.MaxActiveChannels { |
| 1241 | mvp.MaxActiveChannels = uint32(activeChannelCount) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1242 | if err := mvp.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1243 | logger.Errorw(ctx, "Mvlan profile Write to DB failed", log.Fields{"ProfileName": mvp.Name}) |
| 1244 | } |
| 1245 | if prevMaxActiveChannels != mvp.MaxActiveChannels { |
| 1246 | mvp.UpdateActiveChannelSubscriberAlarm() |
| 1247 | } |
| 1248 | } |
| 1249 | mvp.mvpLock.Unlock() |
| 1250 | return nil |
| 1251 | } |
| 1252 | mvp.mvpLock.Unlock() |
| 1253 | mvp.MaxActiveChannels = uint32(activeChannelCount) |
| 1254 | |
| 1255 | // Status is maintained so that in the event of any crash or reboot during update, |
| 1256 | // the recovery is possible once the pod is UP again |
| 1257 | mvp.SetUpdateStatus("", UpdateInProgress) |
| 1258 | mvp.oldGroups = existingGroup |
| 1259 | mvp.oldProxy = existingProxy |
| 1260 | va.storeMvlansMap(vlan, name, mvp) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1261 | if err := mvp.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1262 | logger.Errorw(ctx, "Mvlan profile Write to DB failed", log.Fields{"ProfileName": mvp.Name}) |
| 1263 | } |
| 1264 | if prevMaxActiveChannels != mvp.MaxActiveChannels { |
| 1265 | mvp.UpdateActiveChannelSubscriberAlarm() |
| 1266 | } |
| 1267 | |
| 1268 | // The update task is added as part of Igm p task list, so that any parallel igmp pkt processing is avoided |
| 1269 | // Until, the update operation is completed, the igmp pkt processing will be enqueued |
| 1270 | updateTask := NewUpdateMvlanTask(mvp, "") |
| 1271 | va.IgmpTasks.AddTask(updateTask) |
| 1272 | return nil |
| 1273 | } |
| 1274 | |
| 1275 | // isDeviceInList to check if device is the list |
| 1276 | func isDeviceInList(serialNum string, OLTSerialNums []string) bool { |
| 1277 | for _, oltSerialNum := range OLTSerialNums { |
| 1278 | if serialNum == oltSerialNum { |
| 1279 | return true |
| 1280 | } |
| 1281 | } |
| 1282 | return false |
| 1283 | } |
| 1284 | |
| 1285 | // McastConfigKey creates the key using the olt serial number and mvlan profile id |
| 1286 | func McastConfigKey(oltSerialNum string, mvlanProfID string) string { |
| 1287 | return oltSerialNum + "_" + mvlanProfID |
| 1288 | } |
| 1289 | |
| 1290 | // GetMcastConfig to get McastConfig Information by OLT and Mvlan Profile ID |
| 1291 | func (va *VoltApplication) GetMcastConfig(oltSerialNum string, mvlanProfID string) *McastConfig { |
| 1292 | if mc, ok := va.McastConfigMap.Load(McastConfigKey(oltSerialNum, mvlanProfID)); ok { |
| 1293 | return mc.(*McastConfig) |
| 1294 | } |
| 1295 | return nil |
| 1296 | } |
| 1297 | |
| 1298 | func (va *VoltApplication) storeMcastConfig(oltSerialNum string, mvlanProfID string, mcastConfig *McastConfig) { |
| 1299 | va.McastConfigMap.Store(McastConfigKey(oltSerialNum, mvlanProfID), mcastConfig) |
| 1300 | } |
| 1301 | |
| 1302 | func (va *VoltApplication) deleteMcastConfig(oltSerialNum string, mvlanProfID string) { |
| 1303 | va.McastConfigMap.Delete(McastConfigKey(oltSerialNum, mvlanProfID)) |
| 1304 | } |
| 1305 | |
| 1306 | // AddMcastConfig for addition of a MVLAN profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1307 | func (va *VoltApplication) AddMcastConfig(cntx context.Context, MvlanProfileID string, IgmpProfileID string, IgmpProxyIP string, OltSerialNum string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1308 | var mcastCfg *McastConfig |
| 1309 | |
| 1310 | mcastCfg = va.GetMcastConfig(OltSerialNum, MvlanProfileID) |
| 1311 | if mcastCfg == nil { |
| 1312 | mcastCfg = &McastConfig{} |
| 1313 | } else { |
| 1314 | logger.Debugw(ctx, "Mcast Config already exists", log.Fields{"OltSerialNum": mcastCfg.OltSerialNum, |
| 1315 | "MVLAN Profile ID": mcastCfg.MvlanProfileID}) |
| 1316 | } |
| 1317 | |
| 1318 | // Update all igds available |
| 1319 | mvpIntf, ok := va.MvlanProfilesByName.Load(MvlanProfileID) |
| 1320 | if !ok { |
| 1321 | return errors.New("MVLAN profile not found during add mcast config") |
| 1322 | } |
| 1323 | mvlan := mvpIntf.(*MvlanProfile).Mvlan |
| 1324 | |
| 1325 | mcastCfg.OltSerialNum = OltSerialNum |
| 1326 | mcastCfg.MvlanProfileID = MvlanProfileID |
| 1327 | mcastCfg.IgmpProfileID = IgmpProfileID |
| 1328 | mcastCfg.IgmpProxyIP = net.ParseIP(IgmpProxyIP) |
| 1329 | |
| 1330 | proxyCfg := va.getIgmpProfileMap(IgmpProfileID) |
| 1331 | |
| 1332 | iterIgmpGroups := func(key interface{}, value interface{}) bool { |
| 1333 | ig := value.(*IgmpGroup) |
| 1334 | if ig.Mvlan != mvlan { |
| 1335 | return true |
| 1336 | } |
| 1337 | |
| 1338 | for _, igd := range ig.Devices { |
| 1339 | if igd.SerialNo != OltSerialNum { |
| 1340 | continue |
| 1341 | } |
| 1342 | igd.proxyCfg = proxyCfg |
| 1343 | if IgmpProfileID == "" { |
| 1344 | igd.IgmpProxyIP = &igd.proxyCfg.IgmpSourceIP |
| 1345 | } else { |
| 1346 | igd.IgmpProxyIP = &mcastCfg.IgmpProxyIP |
| 1347 | } |
| 1348 | mcastCfg.IgmpGroupDevices.Store(igd.GroupID, igd) |
| 1349 | logger.Debugw(ctx, "Igd updated with proxyCfg and proxyIP", log.Fields{"name": igd.GroupName, |
| 1350 | "IgmpProfileID": IgmpProfileID, "ProxyIP": mcastCfg.IgmpProxyIP}) |
| 1351 | } |
| 1352 | return true |
| 1353 | } |
| 1354 | va.IgmpGroups.Range(iterIgmpGroups) |
| 1355 | |
| 1356 | va.storeMcastConfig(OltSerialNum, MvlanProfileID, mcastCfg) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1357 | if err := mcastCfg.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1358 | logger.Errorw(ctx, "McastConfig Write to DB failed", log.Fields{"OltSerialNum": mcastCfg.OltSerialNum, "MvlanProfileID": mcastCfg.MvlanProfileID}) |
| 1359 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1360 | va.addOltToMvlan(cntx, MvlanProfileID, OltSerialNum) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1361 | |
| 1362 | return nil |
| 1363 | } |
| 1364 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1365 | func (va *VoltApplication) addOltToMvlan(cntx context.Context, MvlanProfileID string, OltSerialNum string) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1366 | var mvp *MvlanProfile |
| 1367 | if mvpIntf, ok := va.MvlanProfilesByName.Load(MvlanProfileID); ok { |
| 1368 | servVersion := IgmpVersion0 |
| 1369 | mvp = mvpIntf.(*MvlanProfile) |
| 1370 | mvp.DevicesList[OltSerialNum] = NoOp |
| 1371 | mvp.IgmpServVersion[OltSerialNum] = &servVersion |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1372 | if err := mvp.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1373 | logger.Errorw(ctx, "Mvlan profile Write to DB failed", log.Fields{"ProfileName": mvp.Name}) |
| 1374 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1375 | mvp.pushIgmpMcastFlows(cntx, OltSerialNum) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1376 | } |
| 1377 | } |
| 1378 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1379 | func (va *VoltApplication) delOltFromMvlan(cntx context.Context, MvlanProfileID string, OltSerialNum string) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1380 | var mvp *MvlanProfile |
| 1381 | if mvpIntf, ok := va.MvlanProfilesByName.Load(MvlanProfileID); ok { |
| 1382 | mvp = mvpIntf.(*MvlanProfile) |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1383 | // Delete from mvp list |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1384 | mvp.removeIgmpMcastFlows(cntx, OltSerialNum) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1385 | delete(mvp.DevicesList, OltSerialNum) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1386 | if err := mvp.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1387 | logger.Errorw(ctx, "Mvlan profile Write to DB failed", log.Fields{"ProfileName": mvp.Name}) |
| 1388 | } |
| 1389 | } |
| 1390 | } |
| 1391 | |
| 1392 | // DelMcastConfig for addition of a MVLAN profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1393 | func (va *VoltApplication) DelMcastConfig(cntx context.Context, MvlanProfileID string, IgmpProfileID string, IgmpProxyIP string, OltSerialNum string) { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1394 | va.delOltFromMvlan(cntx, MvlanProfileID, OltSerialNum) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1395 | va.deleteMcastConfig(OltSerialNum, MvlanProfileID) |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1396 | _ = db.DelMcastConfig(cntx, McastConfigKey(OltSerialNum, MvlanProfileID)) |
Tinoj Joseph | 50d722c | 2022-12-06 22:53:22 +0530 | [diff] [blame] | 1397 | if d, _ := va.GetDeviceBySerialNo(OltSerialNum); d != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1398 | if mvp := va.GetMvlanProfileByName(MvlanProfileID); mvp != nil { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1399 | va.RemoveGroupsFromPendingPool(cntx, d.Name, mvp.Mvlan) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1400 | } |
| 1401 | } |
| 1402 | } |
| 1403 | |
| 1404 | // DelAllMcastConfig for deletion of all mcast config |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1405 | func (va *VoltApplication) DelAllMcastConfig(cntx context.Context, OltSerialNum string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1406 | deleteIndividualMcastConfig := func(key interface{}, value interface{}) bool { |
| 1407 | mcastCfg := value.(*McastConfig) |
| 1408 | if mcastCfg.OltSerialNum == OltSerialNum { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1409 | va.DelMcastConfig(cntx, mcastCfg.MvlanProfileID, mcastCfg.IgmpProfileID, mcastCfg.IgmpProxyIP.String(), mcastCfg.OltSerialNum) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1410 | } |
| 1411 | return true |
| 1412 | } |
| 1413 | va.McastConfigMap.Range(deleteIndividualMcastConfig) |
| 1414 | return nil |
| 1415 | } |
| 1416 | |
| 1417 | // UpdateMcastConfig for addition of a MVLAN profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1418 | func (va *VoltApplication) UpdateMcastConfig(cntx context.Context, MvlanProfileID string, IgmpProfileID string, IgmpProxyIP string, OltSerialNum string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1419 | mcastCfg := va.GetMcastConfig(OltSerialNum, MvlanProfileID) |
| 1420 | if mcastCfg == nil { |
| 1421 | logger.Warnw(ctx, "Mcast Config not found. Unable to update", log.Fields{"Mvlan Profile ID": MvlanProfileID, "OltSerialNum": OltSerialNum}) |
| 1422 | return nil |
| 1423 | } |
| 1424 | |
| 1425 | oldProfID := mcastCfg.IgmpProfileID |
| 1426 | mcastCfg.IgmpProfileID = IgmpProfileID |
| 1427 | mcastCfg.IgmpProxyIP = net.ParseIP(IgmpProxyIP) |
| 1428 | |
| 1429 | va.storeMcastConfig(OltSerialNum, MvlanProfileID, mcastCfg) |
| 1430 | |
| 1431 | // Update all igds |
| 1432 | if oldProfID != mcastCfg.IgmpProfileID { |
| 1433 | updateIgdProxyCfg := func(key interface{}, value interface{}) bool { |
| 1434 | igd := value.(*IgmpGroupDevice) |
| 1435 | igd.proxyCfg = va.getIgmpProfileMap(mcastCfg.IgmpProfileID) |
| 1436 | if IgmpProfileID == "" { |
| 1437 | igd.IgmpProxyIP = &igd.proxyCfg.IgmpSourceIP |
| 1438 | } else { |
| 1439 | igd.IgmpProxyIP = &mcastCfg.IgmpProxyIP |
| 1440 | } |
| 1441 | return true |
| 1442 | } |
| 1443 | mcastCfg.IgmpGroupDevices.Range(updateIgdProxyCfg) |
| 1444 | } |
| 1445 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1446 | if err := mcastCfg.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1447 | logger.Errorw(ctx, "McastConfig Write to DB failed", log.Fields{"OltSerialNum": mcastCfg.OltSerialNum, "MvlanProfileID": mcastCfg.MvlanProfileID}) |
| 1448 | } |
| 1449 | |
| 1450 | return nil |
| 1451 | } |
| 1452 | |
| 1453 | // WriteToDb is utility to write Mcast config Info to database |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1454 | func (mc *McastConfig) WriteToDb(cntx context.Context) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1455 | mc.Version = database.PresentVersionMap[database.McastConfigPath] |
| 1456 | b, err := json.Marshal(mc) |
| 1457 | if err != nil { |
| 1458 | return err |
| 1459 | } |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1460 | if err1 := db.PutMcastConfig(cntx, McastConfigKey(mc.OltSerialNum, mc.MvlanProfileID), string(b)); err1 != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1461 | return err1 |
| 1462 | } |
| 1463 | return nil |
| 1464 | } |
| 1465 | |
| 1466 | // RestoreMcastConfigsFromDb to read from the DB and restore Mcast configs |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1467 | func (va *VoltApplication) RestoreMcastConfigsFromDb(cntx context.Context) { |
| 1468 | mcastConfigs, _ := db.GetMcastConfigs(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1469 | for hash, mcastConfig := range mcastConfigs { |
| 1470 | b, ok := mcastConfig.Value.([]byte) |
| 1471 | if !ok { |
| 1472 | logger.Warn(ctx, "The value type is not []byte") |
| 1473 | continue |
| 1474 | } |
| 1475 | var mc McastConfig |
| 1476 | err := json.Unmarshal(b, &mc) |
| 1477 | if err != nil { |
| 1478 | logger.Warn(ctx, "Unmarshal of Mcast config failed") |
| 1479 | continue |
| 1480 | } |
| 1481 | va.storeMcastConfig(mc.OltSerialNum, mc.MvlanProfileID, &mc) |
| 1482 | logger.Infow(ctx, "Restored Mcast config", log.Fields{"OltSerialNum": mc.OltSerialNum, "MvlanProfileID": mc.MvlanProfileID, "hash": hash}) |
| 1483 | } |
| 1484 | } |
| 1485 | |
| 1486 | // AddMvlanProfile for addition of a MVLAN profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1487 | func (va *VoltApplication) AddMvlanProfile(cntx context.Context, name string, mvlan of.VlanType, ponVlan of.VlanType, |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1488 | groups map[string][]string, isChannelBasedGroup bool, OLTSerialNum []string, activeChannelsPerPon int, proxy map[string]common.MulticastGroupProxy) error { |
| 1489 | var mvp *MvlanProfile |
| 1490 | |
| 1491 | if mvp = va.GetMvlanProfileByTag(mvlan); mvp != nil { |
| 1492 | logger.Errorw(ctx, "Duplicate MVLAN ID configured", log.Fields{"mvlan": mvlan}) |
| 1493 | return errors.New("MVLAN profile with same VLANID exists") |
| 1494 | } |
| 1495 | if mvpIntf, ok := va.MvlanProfilesByName.Load(name); ok { |
| 1496 | mvp = mvpIntf.(*MvlanProfile) |
| 1497 | for _, serialNum := range OLTSerialNum { |
| 1498 | if mvp.DevicesList[serialNum] != Nil { |
| 1499 | //This is backup restore scenario, just update the profile |
| 1500 | logger.Info(ctx, "Add Mvlan : Profile Name already exists, update-the-profile") |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1501 | return va.UpdateMvlanProfile(cntx, name, mvlan, groups, activeChannelsPerPon, proxy) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1502 | } |
| 1503 | } |
| 1504 | } |
| 1505 | |
| 1506 | if mvp == nil { |
| 1507 | mvp = NewMvlanProfile(name, mvlan, ponVlan, isChannelBasedGroup, OLTSerialNum, uint32(activeChannelsPerPon)) |
| 1508 | } |
| 1509 | |
| 1510 | va.storeMvlansMap(mvlan, name, mvp) |
| 1511 | |
| 1512 | /* Need to protect groups and proxy write lock */ |
| 1513 | mvp.mvpLock.Lock() |
| 1514 | for grpName, grpInfo := range groups { |
| 1515 | mvp.AddMvlanGroup(grpName, grpInfo) |
| 1516 | } |
| 1517 | for grpName, proxyInfo := range proxy { |
| 1518 | mvp.AddMvlanProxy(grpName, proxyInfo) |
| 1519 | } |
| 1520 | if _, ok := mvp.Groups[common.StaticGroup]; ok { |
| 1521 | if _, yes := mvp.Proxy[common.StaticGroup]; !yes { |
| 1522 | mvp.Groups[common.StaticGroup].IsStatic = true |
| 1523 | } |
| 1524 | } |
| 1525 | |
| 1526 | logger.Debugw(ctx, "Added MVLAN Profile", log.Fields{"MVLAN": mvp.Mvlan, "PonVlan": mvp.PonVlan, "Name": mvp.Name, "Grp IPs": mvp.Groups, "IsPonVlanPresent": mvp.IsPonVlanPresent}) |
| 1527 | mvp.mvpLock.Unlock() |
| 1528 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1529 | if err := mvp.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1530 | logger.Errorw(ctx, "Mvlan profile Write to DB failed", log.Fields{"ProfileName": mvp.Name}) |
| 1531 | } |
| 1532 | |
| 1533 | return nil |
| 1534 | } |
| 1535 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1536 | // GetMvlanProfileForMcIP - Get an MVLAN profile for a given MC IP. This is used when an |
| 1537 | // IGMP report is received from the PON port. The MVLAN profile |
| 1538 | // located is used to idnetify the MC VLAN used in upstream for |
| 1539 | // join/leave |
| 1540 | func (va *VoltApplication) GetMvlanProfileForMcIP(profileName string, ip net.IP) (*MvlanProfile, string) { |
| 1541 | if mvpIntf, ok := va.MvlanProfilesByName.Load(profileName); ok { |
| 1542 | mvp := mvpIntf.(*MvlanProfile) |
| 1543 | if grpName := mvp.GetMvlanGroup(ip); grpName != "" { |
| 1544 | return mvp, grpName |
| 1545 | } |
| 1546 | } else { |
| 1547 | logger.Warnw(ctx, "Mvlan Profile not found for given profile name", log.Fields{"Profile": profileName}) |
| 1548 | } |
| 1549 | return nil, "" |
| 1550 | } |
| 1551 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1552 | // IgmpTick for igmp tick info |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1553 | func (va *VoltApplication) IgmpTick(cntx context.Context) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1554 | tickCount++ |
| 1555 | if (tickCount % 1000) == 0 { |
| 1556 | logger.Debugw(ctx, "Time @ Tick", log.Fields{"Tick": tickCount, "Time": time.Now()}) |
| 1557 | } |
| 1558 | igmptick := func(key interface{}, value interface{}) bool { |
| 1559 | ig := value.(*IgmpGroup) |
| 1560 | if ig.NumDevicesActive() != 0 { |
| 1561 | if tickCount%10 == ig.Hash()%10 { |
| 1562 | ig.IgmpGroupLock.Lock() |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1563 | ig.Tick(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1564 | ig.IgmpGroupLock.Unlock() |
| 1565 | if ig.NumDevicesActive() == 0 { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1566 | va.DelIgmpGroup(cntx, ig) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1567 | } |
| 1568 | } |
| 1569 | } |
| 1570 | return true |
| 1571 | } |
| 1572 | va.IgmpGroups.Range(igmptick) |
| 1573 | } |
| 1574 | |
| 1575 | // Tick to add Tick Task |
| 1576 | func (va *VoltApplication) Tick() { |
| 1577 | tt := NewTickTask() |
| 1578 | va.IgmpTasks.AddTask(tt) |
| 1579 | // va.IgmpTick() |
| 1580 | } |
| 1581 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1582 | // AddIgmpProfile for addition of IGMP Profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1583 | func (va *VoltApplication) AddIgmpProfile(cntx context.Context, igmpProfileConfig *common.IGMPConfig) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1584 | var igmpProfile *IgmpProfile |
| 1585 | |
| 1586 | if igmpProfileConfig.ProfileID == DefaultIgmpProfID { |
| 1587 | logger.Info(ctx, "Updating default IGMP profile") |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1588 | return va.UpdateIgmpProfile(cntx, igmpProfileConfig) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1589 | } |
| 1590 | |
| 1591 | igmpProfile = va.checkIgmpProfileMap(igmpProfileConfig.ProfileID) |
| 1592 | if igmpProfile == nil { |
| 1593 | igmpProfile = newIgmpProfile(igmpProfileConfig) |
| 1594 | } else { |
| 1595 | logger.Errorw(ctx, "IGMP profile already exists", log.Fields{"IgmpProfile": igmpProfileConfig.ProfileID}) |
| 1596 | return errors.New("IGMP Profile already exists") |
| 1597 | } |
| 1598 | |
| 1599 | va.storeIgmpProfileMap(igmpProfileConfig.ProfileID, igmpProfile) |
| 1600 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1601 | if err := igmpProfile.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1602 | logger.Errorw(ctx, "Igmp profile Write to DB failed", log.Fields{"profileID": igmpProfile.ProfileID}) |
| 1603 | } |
| 1604 | |
| 1605 | return nil |
| 1606 | } |
| 1607 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1608 | // checkIgmpProfileMap to get Igmp Profile. If not found return nil |
| 1609 | func (va *VoltApplication) checkIgmpProfileMap(name string) *IgmpProfile { |
| 1610 | if igmpProfileIntf, ok := va.IgmpProfilesByName.Load(name); ok { |
| 1611 | return igmpProfileIntf.(*IgmpProfile) |
| 1612 | } |
| 1613 | return nil |
| 1614 | } |
| 1615 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1616 | func (va *VoltApplication) resetIgmpProfileToDefault(cntx context.Context) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1617 | igmpProf := va.getIgmpProfileMap(DefaultIgmpProfID) |
| 1618 | defIgmpProf := newDefaultIgmpProfile() |
| 1619 | |
| 1620 | igmpProf.UnsolicitedTimeOut = defIgmpProf.UnsolicitedTimeOut |
| 1621 | igmpProf.MaxResp = defIgmpProf.MaxResp |
| 1622 | igmpProf.KeepAliveInterval = defIgmpProf.KeepAliveInterval |
| 1623 | igmpProf.KeepAliveCount = defIgmpProf.KeepAliveCount |
| 1624 | igmpProf.LastQueryInterval = defIgmpProf.LastQueryInterval |
| 1625 | igmpProf.LastQueryCount = defIgmpProf.LastQueryCount |
| 1626 | igmpProf.FastLeave = defIgmpProf.FastLeave |
| 1627 | igmpProf.PeriodicQuery = defIgmpProf.PeriodicQuery |
| 1628 | igmpProf.IgmpCos = defIgmpProf.IgmpCos |
| 1629 | igmpProf.WithRAUpLink = defIgmpProf.WithRAUpLink |
| 1630 | igmpProf.WithRADownLink = defIgmpProf.WithRADownLink |
| 1631 | igmpProf.IgmpVerToServer = defIgmpProf.IgmpVerToServer |
| 1632 | igmpProf.IgmpSourceIP = defIgmpProf.IgmpSourceIP |
| 1633 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1634 | if err := igmpProf.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1635 | logger.Errorw(ctx, "Igmp profile Write to DB failed", log.Fields{"profileID": igmpProf.ProfileID}) |
| 1636 | } |
| 1637 | } |
| 1638 | |
| 1639 | // getIgmpProfileMap to get Igmp Profile. If not found return default IGMP config |
| 1640 | func (va *VoltApplication) getIgmpProfileMap(name string) *IgmpProfile { |
| 1641 | if igmpProfileIntf, ok := va.IgmpProfilesByName.Load(name); ok { |
| 1642 | return igmpProfileIntf.(*IgmpProfile) |
| 1643 | } |
| 1644 | |
| 1645 | // There will be always a default igmp profile. |
| 1646 | defaultIgmpProfileIntf, _ := va.IgmpProfilesByName.Load(DefaultIgmpProfID) |
| 1647 | return defaultIgmpProfileIntf.(*IgmpProfile) |
| 1648 | } |
| 1649 | |
| 1650 | // storeIgmpProfileMap to store Igmp Profile |
| 1651 | func (va *VoltApplication) storeIgmpProfileMap(name string, igmpProfile *IgmpProfile) { |
| 1652 | va.IgmpProfilesByName.Store(name, igmpProfile) |
| 1653 | } |
| 1654 | |
| 1655 | // deleteIgmpProfileMap to delete Igmp Profile |
| 1656 | func (va *VoltApplication) deleteIgmpProfileMap(name string) { |
| 1657 | va.IgmpProfilesByName.Delete(name) |
| 1658 | } |
| 1659 | |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1660 | // TODO - DelIgmpProfile for deleting IGMP Profile based on profile Id |
| 1661 | // func (va *VoltApplication) DelIgmpProfile(cntx context.Context, igmpProfileConfig *common.IGMPConfig) error { |
| 1662 | // // Deletion of default igmp profile is blocked from submgr. Keeping additional check for safety. |
| 1663 | // if igmpProfileConfig.ProfileID == DefaultIgmpProfID { |
| 1664 | // logger.Info(ctx, "Resetting default IGMP profile") |
| 1665 | // va.resetIgmpProfileToDefault(cntx) |
| 1666 | // return nil |
| 1667 | // } |
| 1668 | // igmpProfile := va.checkIgmpProfileMap(igmpProfileConfig.ProfileID) |
| 1669 | // if igmpProfile == nil { |
| 1670 | // logger.Warnw(ctx, "Igmp Profile not found. Unable to delete", log.Fields{"Profile ID": igmpProfileConfig.ProfileID}) |
| 1671 | // return nil |
| 1672 | // } |
| 1673 | |
| 1674 | // va.deleteIgmpProfileMap(igmpProfileConfig.ProfileID) |
| 1675 | |
| 1676 | // _ = db.DelIgmpProfile(cntx, igmpProfileConfig.ProfileID) |
| 1677 | |
| 1678 | // return nil |
| 1679 | // } |
| 1680 | |
| 1681 | // DelIgmpProfile for deleting IGMP Profile based on profile Id |
| 1682 | func (va *VoltApplication) DelIgmpProfile(cntx context.Context, profileID string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1683 | // Deletion of default igmp profile is blocked from submgr. Keeping additional check for safety. |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1684 | if profileID == DefaultIgmpProfID { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1685 | logger.Info(ctx, "Resetting default IGMP profile") |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1686 | va.resetIgmpProfileToDefault(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1687 | return nil |
| 1688 | } |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1689 | igmpProfile := va.checkIgmpProfileMap(profileID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1690 | if igmpProfile == nil { |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1691 | logger.Warnw(ctx, "Igmp Profile not found. Unable to delete", log.Fields{"Profile ID": profileID}) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1692 | return nil |
| 1693 | } |
| 1694 | |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1695 | va.deleteIgmpProfileMap(profileID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1696 | |
Akash Soni | a824697 | 2023-01-03 10:37:08 +0530 | [diff] [blame] | 1697 | err := db.DelIgmpProfile(cntx, profileID) |
| 1698 | if err != nil { |
| 1699 | logger.Errorw(ctx, "Failed to delete Igmp profile from DB", log.Fields{"Error": err}) |
| 1700 | return err |
| 1701 | } |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1702 | |
| 1703 | return nil |
| 1704 | } |
| 1705 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1706 | // UpdateIgmpProfile for addition of IGMP Profile |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1707 | func (va *VoltApplication) UpdateIgmpProfile(cntx context.Context, igmpProfileConfig *common.IGMPConfig) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1708 | igmpProfile := va.checkIgmpProfileMap(igmpProfileConfig.ProfileID) |
| 1709 | if igmpProfile == nil { |
| 1710 | logger.Errorw(ctx, "Igmp Profile not found. Unable to update", log.Fields{"Profile ID": igmpProfileConfig.ProfileID}) |
| 1711 | return errors.New("IGMP Profile not found") |
| 1712 | } |
| 1713 | |
| 1714 | igmpProfile.ProfileID = igmpProfileConfig.ProfileID |
| 1715 | igmpProfile.UnsolicitedTimeOut = uint32(igmpProfileConfig.UnsolicitedTimeOut) |
| 1716 | igmpProfile.MaxResp = uint32(igmpProfileConfig.MaxResp) |
| 1717 | |
| 1718 | keepAliveInterval := uint32(igmpProfileConfig.KeepAliveInterval) |
| 1719 | |
vinokuma | 926cb3e | 2023-03-29 11:41:06 +0530 | [diff] [blame] | 1720 | // KeepAliveInterval should have a min of 10 seconds |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1721 | if keepAliveInterval < MinKeepAliveInterval { |
| 1722 | keepAliveInterval = MinKeepAliveInterval |
| 1723 | logger.Infow(ctx, "Auto adjust keepAliveInterval - Value < 10", log.Fields{"Received": igmpProfileConfig.KeepAliveInterval, "Configured": keepAliveInterval}) |
| 1724 | } |
| 1725 | igmpProfile.KeepAliveInterval = keepAliveInterval |
| 1726 | |
| 1727 | igmpProfile.KeepAliveCount = uint32(igmpProfileConfig.KeepAliveCount) |
| 1728 | igmpProfile.LastQueryInterval = uint32(igmpProfileConfig.LastQueryInterval) |
| 1729 | igmpProfile.LastQueryCount = uint32(igmpProfileConfig.LastQueryCount) |
| 1730 | igmpProfile.FastLeave = *igmpProfileConfig.FastLeave |
| 1731 | igmpProfile.PeriodicQuery = *igmpProfileConfig.PeriodicQuery |
| 1732 | igmpProfile.IgmpCos = uint8(igmpProfileConfig.IgmpCos) |
| 1733 | igmpProfile.WithRAUpLink = *igmpProfileConfig.WithRAUpLink |
| 1734 | igmpProfile.WithRADownLink = *igmpProfileConfig.WithRADownLink |
| 1735 | |
| 1736 | if igmpProfileConfig.IgmpVerToServer == "2" || igmpProfileConfig.IgmpVerToServer == "v2" { |
| 1737 | igmpProfile.IgmpVerToServer = "2" |
| 1738 | } else { |
| 1739 | igmpProfile.IgmpVerToServer = "3" |
| 1740 | } |
| 1741 | |
| 1742 | if igmpProfileConfig.IgmpSourceIP != "" { |
| 1743 | igmpProfile.IgmpSourceIP = net.ParseIP(igmpProfileConfig.IgmpSourceIP) |
| 1744 | } |
| 1745 | |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1746 | if err := igmpProfile.WriteToDb(cntx); err != nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1747 | logger.Errorw(ctx, "Igmp profile Write to DB failed", log.Fields{"profileID": igmpProfile.ProfileID}) |
| 1748 | } |
| 1749 | |
| 1750 | return nil |
| 1751 | } |
| 1752 | |
| 1753 | // RestoreIGMPProfilesFromDb to read from the DB and restore IGMP Profiles |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1754 | func (va *VoltApplication) RestoreIGMPProfilesFromDb(cntx context.Context) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1755 | // Loading IGMP profiles |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1756 | igmpProfiles, _ := db.GetIgmpProfiles(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1757 | for _, igmpProfile := range igmpProfiles { |
| 1758 | b, ok := igmpProfile.Value.([]byte) |
| 1759 | if !ok { |
| 1760 | logger.Warn(ctx, "The value type is not []byte") |
| 1761 | continue |
| 1762 | } |
| 1763 | var igmpProf IgmpProfile |
| 1764 | err := json.Unmarshal(b, &igmpProf) |
| 1765 | if err != nil { |
| 1766 | logger.Warn(ctx, "Unmarshal of IGMP Profile failed") |
| 1767 | continue |
| 1768 | } |
| 1769 | va.storeIgmpProfileMap(igmpProf.ProfileID, &igmpProf) |
| 1770 | logger.Infow(ctx, "Restored Igmp Profile", log.Fields{"Conf": igmpProf}) |
| 1771 | } |
| 1772 | } |
| 1773 | |
| 1774 | // InitIgmpSrcMac for initialization of igmp source mac |
| 1775 | func (va *VoltApplication) InitIgmpSrcMac() { |
| 1776 | srcMac, err := getPodMacAddr() |
| 1777 | if err != nil { |
| 1778 | igmpSrcMac = "00:11:11:11:11:11" |
| 1779 | return |
| 1780 | } |
| 1781 | igmpSrcMac = srcMac |
| 1782 | } |
| 1783 | |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1784 | // DelMvlanProfile for deletion of a MVLAN group |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1785 | func (va *VoltApplication) DelMvlanProfile(cntx context.Context, name string) error { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1786 | if mvpIntf, ok := va.MvlanProfilesByName.Load(name); ok { |
| 1787 | mvp := mvpIntf.(*MvlanProfile) |
| 1788 | |
| 1789 | if len(mvp.DevicesList) == 0 { |
| 1790 | mvp.DeleteInProgress = true |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1791 | mvp.DelFromDb(cntx) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1792 | va.deleteMvlansMap(mvp.Mvlan, name) |
| 1793 | logger.Debugw(ctx, "Deleted MVLAN Profile", log.Fields{"Name": mvp.Name}) |
| 1794 | } else { |
| 1795 | logger.Errorw(ctx, "Unable to delete Mvlan Profile as there is still an OLT attached to it", log.Fields{"Name": mvp.Name, |
| 1796 | "Device List": mvp.DevicesList}) |
| 1797 | return errors.New("MVLAN attached to devices") |
| 1798 | } |
| 1799 | |
| 1800 | return nil |
| 1801 | } |
| 1802 | logger.Errorw(ctx, "MVLAN Profile not found", log.Fields{"MvlanProfile Name": name}) |
| 1803 | return nil |
| 1804 | } |
| 1805 | |
| 1806 | // ReceiverUpInd for receiver up indication |
| 1807 | func (va *VoltApplication) ReceiverUpInd(device string, port string, mvpName string, vlan of.VlanType, pbits []of.PbitType) { |
| 1808 | logger.Infow(ctx, "Receiver Indication: UP", log.Fields{"device": device, "port": port, "MVP": mvpName, "vlan": vlan, "pbits": pbits}) |
| 1809 | if mvpIntf, ok := va.MvlanProfilesByName.Load(mvpName); ok { |
| 1810 | mvp := mvpIntf.(*MvlanProfile) |
| 1811 | if devIntf, ok := va.DevicesDisc.Load(device); ok { |
| 1812 | dev := devIntf.(*VoltDevice) |
| 1813 | proxyCfg, proxyIP, _ := getIgmpProxyCfgAndIP(mvp.Mvlan, dev.SerialNum) |
| 1814 | for _, pbit := range pbits { |
| 1815 | sendGeneralQuery(device, port, vlan, uint8(pbit), proxyCfg, proxyIP) |
| 1816 | } |
| 1817 | } else { |
| 1818 | logger.Warnw(ctx, "Device not found for given port", log.Fields{"device": device, "port": port}) |
| 1819 | } |
| 1820 | } else { |
| 1821 | logger.Warnw(ctx, "Mvlan Profile not found for given profileName", log.Fields{"MVP": mvpName, "vlan": vlan}) |
| 1822 | } |
| 1823 | } |
| 1824 | |
| 1825 | // sendGeneralQuery to send general query |
| 1826 | func sendGeneralQuery(device string, port string, cVlan of.VlanType, pbit uint8, proxyCfg *IgmpProfile, proxyIP *net.IP) { |
Tinoj Joseph | cf161be | 2022-07-07 19:47:47 +0530 | [diff] [blame] | 1827 | if queryPkt, err := Igmpv2QueryPacket(AllSystemsMulticastGroupIP, cVlan, *proxyIP, pbit, proxyCfg.MaxResp); err == nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1828 | if err := cntlr.GetController().PacketOutReq(device, port, port, queryPkt, false); err != nil { |
| 1829 | logger.Warnw(ctx, "General Igmpv2 Query Failed to send", log.Fields{"Device": device, "Port": port, "Packet": queryPkt, "Pbit": pbit}) |
| 1830 | } else { |
| 1831 | logger.Debugw(ctx, "General Igmpv2 Query Sent", log.Fields{"Device": device, "Port": port, "Packet": queryPkt, "Pbit": pbit}) |
| 1832 | } |
| 1833 | } |
| 1834 | if getVersion(proxyCfg.IgmpVerToServer) == IgmpVersion3 { |
Tinoj Joseph | cf161be | 2022-07-07 19:47:47 +0530 | [diff] [blame] | 1835 | if queryPkt, err := Igmpv3QueryPacket(AllSystemsMulticastGroupIP, cVlan, *proxyIP, pbit, proxyCfg.MaxResp); err == nil { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1836 | if err := cntlr.GetController().PacketOutReq(device, port, port, queryPkt, false); err != nil { |
| 1837 | logger.Warnw(ctx, "General Igmpv3 Query Failed to send", log.Fields{"Device": device, "Port": port, "Packet": queryPkt, "Pbit": pbit}) |
| 1838 | } else { |
| 1839 | logger.Debugw(ctx, "General Igmpv3 Query Sent", log.Fields{"Device": device, "Port": port, "Packet": queryPkt, "Pbit": pbit}) |
| 1840 | } |
| 1841 | } |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | // ReceiverDownInd to send receiver down indication |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1846 | func (va *VoltApplication) ReceiverDownInd(cntx context.Context, device string, port string) { |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1847 | logger.Infow(ctx, " Receiver Indication: DOWN", log.Fields{"device": device, "port": port}) |
| 1848 | |
| 1849 | ponPortID := va.GetPonPortID(device, port) |
| 1850 | |
| 1851 | del := func(key interface{}, value interface{}) bool { |
| 1852 | ig := value.(*IgmpGroup) |
| 1853 | ig.IgmpGroupLock.Lock() |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1854 | ig.DelReceiveronDownInd(cntx, device, port, ponPortID) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1855 | ig.IgmpGroupLock.Unlock() |
| 1856 | if ig.NumDevicesActive() == 0 { |
Tinoj Joseph | 07cc537 | 2022-07-18 22:53:51 +0530 | [diff] [blame] | 1857 | va.DelIgmpGroup(cntx, ig) |
Naveen Sampath | 04696f7 | 2022-06-13 15:19:14 +0530 | [diff] [blame] | 1858 | } |
| 1859 | return true |
| 1860 | } |
| 1861 | va.IgmpGroups.Range(del) |
| 1862 | } |