blob: bf8067cc1ce23f44e1a82f7a10299f43fa1b95a5 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/******************************************************************************
2 *
3 * <:copyright-BRCM:2016:DUAL/GPL:standard
4 *
5 * Copyright (c) 2016 Broadcom
6 * All Rights Reserved
7 *
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed
10 * to you under the terms of the GNU General Public License version 2
11 * (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
12 * with the following added to such license:
13 *
14 * As a special exception, the copyright holders of this software give
15 * you permission to link this software with independent modules, and
16 * to copy and distribute the resulting executable under terms of your
17 * choice, provided that you also meet, for each linked independent
18 * module, the terms and conditions of the license of that module.
19 * An independent module is a module which is not derived from this
20 * software. The special exception does not apply to any modifications
21 * of the software.
22 *
23 * Not withstanding the above, under no circumstances may you combine
24 * this software in any way with any other Broadcom software provided
25 * under a license other than the GPL, without Broadcom's express prior
26 * written consent.
27 *
28 * :>
29 *
30 *****************************************************************************/
31
32/**
33 * @file bal_dpp_flow.c
34 * @brief BAL Switch util functions that handle flow requests
35 * @addtogroup sw_util
36 */
37
38 /*@{*/
39#include <bal_common.h>
40#include <bcm_dev_log.h>
41#include <bal_msg.h>
42#include <bal_utils_msg.h>
43#include "bal_switch_flow.h"
44#include "flow_fsm.h"
45#include "bcmos_errno.h"
46#include "bal_switch_util.h"
47#include "bal_dpp_qos_map.h"
48
49#ifndef TEST_SW_UTIL_LOOPBACK
50#define _SHR_PBMP_WIDTH 567
51 /* match the WIDTH size of bcm_field_group_config_t in bcm/field.h with ARAD */
52 /* we build swich_util without #define created by the sdk make/Make.local */
53#include <bcm/types.h>
54#include <sal/core/libc.h>
55#ifndef sal_memset
56#define sal_memset memset
57#endif
58#include <bcm/port.h>
59#include <bcm/vlan.h>
60#include <bcm/field.h>
61#include <bcm/error.h>
62#include <bcm/vswitch.h>
63#include <bcm/qos.h>
64#include <bcm/l2.h>
65
66#include "bal_switch_acc_term.h"
67#include "bal_dpp_flow.h"
68#include "bal_dpp_qos.h"
69#include "bal_dpp_vswitch.h"
70#include "bal_dpp_group.h"
71
72/** Local routines declarations */
73static bcmos_errno bal_sw_util_reverse_flow_create(bcmbal_flow_cfg *p_flow, bcmbal_flow_cfg *p_flow_rev);
74static bcmos_bool bal_sw_util_is_symmetry_flows(bcmbal_flow_cfg *p_flow, bcmbal_flow_cfg *p_ref_flow);
75
76/* perform initialization before any dpp flow function calls */
77void bal_sw_util_dpp_flow_init(void)
78{
79 /* nothing to do here yet, place holder */
80 return;
81}
82
83/**
84 * @brief The create trap gport function create a trap port that allow TRAP action to
85 * associate with and perform packet trapping to the CPU port.
86 *
87 * @param unit the switch unit this trap port to be created
88 * @param p_trap_gport a pointer that the created gport will be return
89 * @param p_trap_code a pointer that the created trap code will be return
90 * @return bcm error code
91 */
92static int bal_sw_util_create_trap_gport(int unit, bcm_gport_t *p_trap_gport, uint32_t *p_trap_code)
93{
94 int ret, trap_id;
95 bcm_rx_trap_config_t trap_config;
96
97 ret = bcm_rx_trap_type_create(unit, 0, bcmRxTrapUserDefine, &trap_id);
98 if(ret != BCM_E_NONE)
99 {
100 BCM_LOG(ERROR, log_id_sw_util, "create trap type return %d\n", ret);
101 return ret;
102 }
103
104 bcm_rx_trap_config_t_init(&trap_config);
105 trap_config.flags = (BCM_RX_TRAP_UPDATE_DEST | BCM_RX_TRAP_TRAP | BCM_RX_TRAP_REPLACE);
106 trap_config.trap_strength = 0;
107 trap_config.dest_port = BCM_GPORT_LOCAL_CPU;
108 ret = bcm_rx_trap_set(unit, trap_id, &trap_config);
109 if(ret != BCM_E_NONE)
110 {
111 BCM_LOG(ERROR, log_id_sw_util, "set rx trap return %d\n", ret);
112 return ret;
113 }
114 BCM_GPORT_TRAP_SET(*p_trap_gport, trap_id, 7 /* trap_strength */, 0);
115 *p_trap_code = trap_id;
116 return ret;
117}
118/* disable the field group (FG) source ip support to restrict the FG size */
119#define BAL_ACL_FG_SRC_IP_ENABLE 0
120/* create a default field group that used by all default ACL.
121 When a FLOW is created,a LIF is created to direct the packets to a VSwitch.
122 The LIF can only match packet with ingress port and VID.
123 If a FLOW needs to be classified with more attributes, an ACL is created to override the LIF.
124 A default ACL has the same packet classification as the LIF but has lower priority than the overlapped ACL.
125 The default ACL dropped packets that match the LIF but do not match the ACL. This enforce the FLOW
126 to only forward packets with exact match */
127static bcm_field_group_t dpp_dft_group_id = 1;
128/* create a field group that used by all ACL */
129static bcm_field_group_t dpp_group_id = 0;
130/**
131 * @brief Create a field group in the switch ICAP,
132 * The field group allow flow classifier to create ACL rules
133 *
134 * @param unit the switch unit this rule is to be added
135 * @param p_group_id a pointer to a variable that return the created group id
136 * @return error code
137 */
138 static bcmos_errno bal_sw_util_dpp_fg_create(int unit, bcm_field_group_t *p_group_id)
139 {
140 bcm_field_group_status_t fg_status;
141 bcm_field_group_config_t grp;
142 int32_t ret = 0;
143
144 /* VCAP - bcmFieldQualifyStageLookup, ICAP - bcmFieldQualifyStageIngress, ECAP - bcmFieldQualifyStageEgress */
145 /* The DPP resources allow only limit number of qset - indexed by dpp_group_id, create qset when necessary */
146 /* create one if not exist */
147 if (BCM_E_NOT_FOUND == bcm_field_group_status_get(unit, *p_group_id, &fg_status))
148 {
149 bcm_field_group_config_t_init(&grp);
150
151 BCM_FIELD_QSET_INIT(grp.qset);
152 /* TCAM entry limit to 80 bits per slice, but up to 4 slices for a group
153 use ModeAuto to automatically adjust it */
154 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyInPort); /* 32 bits */
155 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyDstMac); /* 48 bits */
156 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifySrcMac); /* 48 bits */
157 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyDstIp); /* 32 bits */
158#if (BAL_ACL_FG_SRC_IP_ENABLE == 1)
159 /* save source IP space for other classifier, try to keep total size under 4 slices */
160 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifySrcIp); /* 32 bits */
161#endif
162 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyEtherType); /* 16 bits */
163 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyIpProtocol); /* 8 bits */
164 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyL4DstPort); /* 16 bits */
165 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyL4SrcPort); /* 16 bits */
166 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyOuterVlanId); /* 16 bits */
167 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyOuterVlanPri); /* 8 bits */
168 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyInnerVlanId); /* 16 bits */
169 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyInnerVlanPri); /* 8 bits */
170 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyInVPort); /* 32 bits */
171 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyPacketRes);
172
173 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyStageIngress);
174
175 BCM_FIELD_ASET_INIT(grp.aset);
176 BCM_FIELD_ASET_ADD(grp.aset, bcmFieldActionTrap);
177 BCM_FIELD_ASET_ADD(grp.aset, bcmFieldActionDrop);
178 BCM_FIELD_ASET_ADD(grp.aset, bcmFieldActionRedirect);
179 BCM_FIELD_ASET_ADD(grp.aset, bcmFieldActionVportNew);
180
181 grp.priority = 12; /* the higher the number the higher the priority */
182 grp.flags = (BCM_FIELD_GROUP_CREATE_WITH_MODE | BCM_FIELD_GROUP_CREATE_WITH_ASET);
183 grp.mode = bcmFieldGroupModeAuto;
184
185 ret = bcm_field_group_config_create(unit, &grp);
186
187 if (ret != BCM_E_NONE)
188 {
189 BCM_LOG(ERROR, log_id_sw_util,
190 " flow fail to create field - %d\n", ret );
191 return BCM_ERR_INTERNAL;
192 }
193
194 *p_group_id = grp.group;
195 BCM_LOG(INFO, log_id_sw_util, "Field Group %d created\n", *p_group_id);
196 return BCM_ERR_OK;
197 }
198 return BCM_ERR_ALREADY;
199 }
200
201/**
202 * @brief Create a default field group in the switch ICAP,
203 * This field group allow flow classifier to create default ACL rules
204 *
205 * @param unit the switch unit this rule is to be added
206 * @param p_group_id a pointer to a variable that return the created group id
207 * @return error code
208 */
209 static bcmos_errno bal_sw_util_dpp_dft_fg_create(int unit, bcm_field_group_t *p_group_id)
210 {
211 bcm_field_group_status_t fg_status;
212 bcm_field_group_config_t grp;
213 int32_t ret = 0;
214
215 /* VCAP - bcmFieldQualifyStageLookup, ICAP - bcmFieldQualifyStageIngress, ECAP - bcmFieldQualifyStageEgress */
216 /* The DPP resources allow only limit number of qset - indexed by dpp_group_id, create qset when necessary */
217 /* create one if not exist */
218 if (BCM_E_NOT_FOUND == bcm_field_group_status_get(unit, *p_group_id, &fg_status))
219 {
220 bcm_field_group_config_t_init(&grp);
221
222 BCM_FIELD_QSET_INIT(grp.qset);
223 /* TCAM entry limit to 80 bits per slice, but up to 4 slices for a group
224 use ModeAuto to automatically adjust it */
225
226 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyInVPort); /* 32 bits */
227 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyPacketRes);
228
229 BCM_FIELD_QSET_ADD(grp.qset, bcmFieldQualifyStageIngress);
230
231 BCM_FIELD_ASET_INIT(grp.aset);
232 BCM_FIELD_ASET_ADD(grp.aset, bcmFieldActionDrop);
233
234 grp.priority = 10; /* the higher the number the higher the priority */
235 grp.flags = (BCM_FIELD_GROUP_CREATE_WITH_MODE | BCM_FIELD_GROUP_CREATE_WITH_ASET);
236 grp.mode = bcmFieldGroupModeAuto;
237
238 ret = bcm_field_group_config_create(unit, &grp);
239
240 if (ret != BCM_E_NONE)
241 {
242 BCM_LOG(ERROR, log_id_sw_util,
243 " flow fail to create default field - %d\n", ret );
244 return BCM_ERR_INTERNAL;
245 }
246
247 *p_group_id = grp.group;
248 BCM_LOG(INFO, log_id_sw_util, "Default Field Group %d created\n", *p_group_id);
249 return BCM_ERR_OK;
250 }
251 return BCM_ERR_ALREADY;
252 }
253
254/**
255 * @brief The acl add function add an Access Control Rule in the switch VCAP/ICAP/ECAP
256 * to perform action based on flow classifier
257 *
258 * @param unit the switch unit this rule is to be added
259 * @param p_flow a pointer to the flow definition the created rule will be based on
260 * @param p_flow_elm a pointer to the switch internal flow list
261 * @param in_gport ingress virtual port (LIF) this acl applied
262 * @param out_gport egress virtual port (LIF) this acl applied
263 * @return error code
264 */
265static bcmos_errno bal_sw_util_dpp_acl_add(int unit, bcmbal_flow_cfg *p_flow, bal_sw_flow *p_flow_elm, uint32_t in_gport, uint32_t out_gport)
266{
267 int32_t ret = 0;
268 uint16_t udp_port, flow_pri;
269 bcm_field_entry_t eid;
270 bcm_gport_t trap_gport;
271 bcm_mac_t dst_mac, src_mac;
272 bcm_mac_t mac_mask = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
273 uint32_t trap_code = 0;
274 bcmos_errno err;
275
276 BCM_LOG(INFO, log_id_sw_util,
277 " Add an ACL to a flow w type = %d\n", p_flow->key.flow_type);
278
279 if(p_flow_elm->num_eid >= MAX_FIELD_EID)
280 {
281 BCM_LOG(ERROR, log_id_sw_util, "Too many ACL rules in flow id %d\n", p_flow_elm->id);
282 return BCM_ERR_NORES;
283 }
284
285 err = bal_sw_util_dpp_fg_create(unit, &dpp_group_id);
286
287 if (BCM_ERR_ALREADY != err && BCM_ERR_OK != err)
288 {
289 BCM_LOG(ERROR, log_id_sw_util, "Field Group %d create failed\n", dpp_group_id);
290 return err;
291 }
292
293 /* fill in the match fields */
294 do
295 {
296 ret = bcm_field_entry_create(unit, dpp_group_id, &eid);
297 if (ret)
298 {
299 BCM_LOG(ERROR, log_id_sw_util, "field_entry_create failed - %d\n", ret);
300 break;
301 }
302 /* if upstream, match ingress port */
303 if(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM && BCMBAL_CFG_PROP_IS_SET(p_flow, flow, access_int_id))
304 {
305 ret = bcm_field_qualify_InPort(unit, eid, bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id), 0xffffffff);
306 if (BCM_E_NONE != ret)
307 {
308 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InPort failed - %d\n", ret);
309 break;
310 }
311 else
312 {
313 BCM_LOG(INFO, log_id_sw_util, "Add InPort %d to qualifier\n", bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id));
314 }
315
316 }
317 /* if downstream, match ingress nni port */
318 if(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM && BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id))
319 {
320 ret = bcm_field_qualify_InPort(unit, eid, bal_bcm_net_inf_pbm_get(p_flow->data.network_int_id), 0xffffffff);
321 if (BCM_E_NONE != ret)
322 {
323 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InPort failed - %d\n", ret);
324 break;
325 }
326 else
327 {
328 BCM_LOG(INFO, log_id_sw_util, "Add network port %d to qualifier\n", bal_bcm_net_inf_pbm_get(p_flow->data.network_int_id));
329 }
330 }
331 /* match ether type */
332 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ether_type))
333 {
334 ret = bcm_field_qualify_EtherType(unit, eid, p_flow->data.classifier.ether_type, 0xffff);
335 if (ret)
336 {
337 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_EtherType failed - %d\n", ret);
338 break;
339 }
340 else
341 {
342 BCM_LOG(INFO, log_id_sw_util, "Add ether type 0x%x to qualifier\n", p_flow->data.classifier.ether_type );
343 }
344 }
345 /* add IP protocol to match rule */
346 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, ip_proto))
347 {
348 ret = bcm_field_qualify_IpProtocol(unit, eid, p_flow->data.classifier.ip_proto, 0xff);
349 if (ret)
350 {
351 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_IpProtocol failed - %d\n", ret);
352 break;
353 }
354 else
355 {
356 BCM_LOG(INFO, log_id_sw_util, "Add ip protocol 0x%x to qualifier\n", p_flow->data.classifier.ip_proto );
357 }
358 }
359 /* add L3 source port to match rule - Don't be confused by the API name */
360 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_port))
361 {
362 udp_port = p_flow->data.classifier.src_port;
363 ret = bcm_field_qualify_L4SrcPort(unit, eid, udp_port, 0xffff);
364 if (ret)
365 {
366 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_L4SrcPort failed - %d\n", ret);
367 break;
368 }
369 else
370 {
371 BCM_LOG(INFO, log_id_sw_util, "Add src port %d to qualifier\n", udp_port );
372 }
373 }
374 /* add L3 destination port to match rule */
375 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_port))
376 {
377 udp_port = p_flow->data.classifier.dst_port;
378 ret = bcm_field_qualify_L4DstPort(unit, eid, udp_port, 0xffff);
379 if (ret)
380 {
381 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_L4DstPort failed - %d\n", ret);
382 break;
383 }
384 else
385 {
386 BCM_LOG(INFO, log_id_sw_util, "Add dst port %d to qualifier\n", udp_port );
387 }
388 }
389 /* add Outer vid to match rule */
390 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid))
391 {
392 ret = bcm_field_qualify_OuterVlanId(unit, eid, p_flow->data.classifier.o_vid, 0x0fff);
393 if (ret)
394 {
395 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_OuterVlanId failed - %d\n", ret);
396 break;
397 }
398 else
399 {
400 BCM_LOG(INFO, log_id_sw_util, "Add outer vid 0x%x to qualifier\n", p_flow->data.classifier.o_vid );
401 }
402 }
403 /* add Inner vid to match rule */
404 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid))
405 {
406 ret = bcm_field_qualify_InnerVlanId(unit, eid, p_flow->data.classifier.i_vid, 0x0fff);
407 if (ret)
408 {
409 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InnerVlanId failed - %d\n", ret);
410 break;
411 }
412 else
413 {
414 BCM_LOG(INFO, log_id_sw_util, "Add Inner vid 0x%x to qualifier\n", p_flow->data.classifier.i_vid );
415 }
416 }
417 /* add Outer priority to match rule - only accept 3 bits */
418 /* use ACL for downstream, upstream pbit classification will be done through PON LIF */
419 if(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
420 BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_pbits))
421 {
422 ret = bcm_field_qualify_OuterVlanPri(unit, eid, p_flow->data.classifier.o_pbits, 0x7);
423 if (ret)
424 {
425 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_OuterVlanPri failed - %d\n", ret);
426 break;
427 }
428 else
429 {
430 BCM_LOG(INFO, log_id_sw_util, "Add outer pri 0x%x to qualifier\n", p_flow->data.classifier.o_pbits );
431 }
432 }
433 /* add Inner priority to match rule - only accept 3 bits */
434 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_pbits))
435 {
436 ret = bcm_field_qualify_InnerVlanPri(unit, eid, p_flow->data.classifier.i_pbits, 0x7);
437 if (ret)
438 {
439 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InnerVlanPri failed - %d\n", ret);
440 break;
441 }
442 else
443 {
444 BCM_LOG(INFO, log_id_sw_util, "Add inner pri 0x%x to qualifier\n", p_flow->data.classifier.i_pbits );
445 }
446 }
447 /* add Dst Mac to match rule */
448 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_mac))
449 {
450 memcpy(&dst_mac, &(p_flow->data.classifier.dst_mac), sizeof(bcm_mac_t));
451 ret = bcm_field_qualify_DstMac(unit, eid, dst_mac, mac_mask);
452 if (ret)
453 {
454 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_DstMac failed - %d\n", ret);
455 break;
456 }
457 else
458 {
459 BCM_LOG(INFO, log_id_sw_util, "Add DstMac %x:%x:%x:%x:%x:%x to qualifier\n",
460 p_flow->data.classifier.dst_mac.u8[0],
461 p_flow->data.classifier.dst_mac.u8[1],
462 p_flow->data.classifier.dst_mac.u8[2],
463 p_flow->data.classifier.dst_mac.u8[3],
464 p_flow->data.classifier.dst_mac.u8[4],
465 p_flow->data.classifier.dst_mac.u8[5] );
466 }
467 }
468 /* add Src Mac to match rule */
469 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_mac))
470 {
471 memcpy(&src_mac, &(p_flow->data.classifier.src_mac), sizeof(bcm_mac_t));
472 ret = bcm_field_qualify_SrcMac(unit, eid, src_mac, mac_mask);
473 if (ret)
474 {
475 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_SrcMac failed - %d\n", ret);
476 break;
477 }
478 else
479 {
480 BCM_LOG(INFO, log_id_sw_util, "Add SrcMac[5] 0x%x to qualifier\n", p_flow->data.classifier.src_mac.u8[5] );
481 }
482 }
483 /* add Dst IP to match rule */
484 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_ip))
485 {
486 ret = bcm_field_qualify_DstIp(unit, eid, p_flow->data.classifier.dst_ip.u32, 0xffffffff);
487 if (ret)
488 {
489 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_DstIp failed - %d\n", ret);
490 break;
491 }
492 else
493 {
494 BCM_LOG(INFO, log_id_sw_util, "Add DstIp 0x%x to qualifier\n", p_flow->data.classifier.dst_ip.u32 );
495 }
496 }
497
498 /* add Src IP to match rule */
499 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_ip))
500 {
501 ret = bcm_field_qualify_SrcIp(unit, eid, p_flow->data.classifier.src_ip.u32, 0xffffffff);
502 if (ret)
503 {
504 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_SrcIp failed - %d\n", ret);
505 break;
506 }
507 else
508 {
509 BCM_LOG(INFO, log_id_sw_util, "Add SrcIp 0x%x to qualifier\n", p_flow->data.classifier.src_ip.u32 );
510 }
511 }
512 /* set ACL priority */
513 if(BCMBAL_CFG_PROP_IS_SET(p_flow, flow, priority))
514 {
515 flow_pri = p_flow->data.priority;
516 }
517 else /* default to 10, valid range 0 - 65535 */
518 {
519 flow_pri = BAL_FLOW_DEFAULT_PRIORITY;
520 /* set the presence of priority bit in the flow to reflect insertion of DEFAULT_PRIORITY */
521 BCMBAL_CFG_PROP_SET(p_flow, flow, priority, flow_pri);
522 }
523 ret = bcm_field_entry_prio_set(unit, eid, flow_pri);
524 if (ret)
525 {
526 BCM_LOG(ERROR, log_id_sw_util, "field entry priority failed - %d\n", ret);
527 break;
528 }
529 else
530 {
531 BCM_LOG(INFO, log_id_sw_util, "field entry priority set to - %d\n", flow_pri);
532 }
533
534 }while(0);
535
536 if (BCM_E_NONE == ret) /* make sure the field qualifier settings are good */
537 {
538 if( BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action) &&
539 BCMBAL_ACTION_CMD_ID_IS_SET( &(p_flow->data.action), BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST) )
540 {
541 BCM_LOG(INFO, log_id_sw_util,
542 " Got a flow action cmd=0x%x \n", p_flow->data.action.cmds_bitmask);
543 do
544 {
545 ret = bal_sw_util_create_trap_gport(unit, &trap_gport, &trap_code);
546 if (ret)
547 {
548 BCM_LOG(ERROR, log_id_sw_util, "create_trap_gport failed - %d\n", ret);
549 break;
550 }
551 /* qualify with in LIF */
552 if(in_gport)
553 {
554 /* add vPort to match rule */
555 ret = bcm_field_qualify_InVPort32(unit, eid, in_gport, 0xffff);
556 if (ret)
557 {
558 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InVPort failed - %d\n", ret);
559 break;
560 }
561 }
562 ret = bcm_field_action_add(unit, eid, bcmFieldActionTrap, trap_gport, 0);
563 if (ret)
564 {
565 BCM_LOG(ERROR, log_id_sw_util, "field action add failed - %d\n", ret);
566 break;
567 };
568 ret = bcm_field_entry_install(unit, eid);
569 if (ret)
570 {
571 BCM_LOG(ERROR, log_id_sw_util, "field_entry_install %d failed - %d\n", eid, ret);
572 break;
573 }
574 else
575 {
576 BCM_LOG(INFO, log_id_sw_util, "Add rule %d Success\n", eid);
577 }
578
579 }while(0);
580 }
581 /* regular forwarding ACL */
582 else
583 {
584 do
585 {
586 /* redirect to the egress LIF */
587 ret = bcm_field_action_add(unit, eid, bcmFieldActionRedirect, 0, out_gport);
588 if (ret)
589 {
590 BCM_LOG(ERROR, log_id_sw_util, "field action add failed - %d\n", ret);
591 break;
592 };
593 /* trigger vlan translation at the egress LIF */
594 ret = bcm_field_action_add(unit, eid, bcmFieldActionVportNew, out_gport, 0);
595 if (ret)
596 {
597 BCM_LOG(ERROR, log_id_sw_util, "field action add new vport failed - %d\n", ret);
598 break;
599 };
600
601 ret = bcm_field_entry_install(unit, eid);
602 if (ret)
603 {
604 BCM_LOG(ERROR, log_id_sw_util, "field_entry_install %d failed - %d\n", eid, ret);
605 break;
606 }
607 else
608 {
609 BCM_LOG(INFO, log_id_sw_util, "Add rule %d to gport 0x%x Success\n", eid, out_gport);
610 }
611 }while(0);
612 }
613 }
614
615 if (ret != BCM_E_NONE)
616 {
617 /* TBD - release the eid and trap port resource */
618 return BCM_ERR_INTERNAL;
619 }
620 else
621 {
622 /* add flow info into the internal link list */
623 p_flow_elm->trap_code = trap_code;
624 p_flow_elm->trap_port = trap_gport;
625 p_flow_elm->field_entry_id[p_flow_elm->num_eid] = eid;
626 p_flow_elm->num_eid += 1;
627 p_flow_elm->valid = 1;
628 return BCM_ERR_OK;
629 }
630}
631
632/**
633 * @brief The default acl add function add a DROP Access Control Rule on the ingress LIF
634 *
635 * @param unit the switch unit this rule is to be added
636 * @param p_flow a pointer to the flow definition the created rule will be based on
637 * @param p_flow_elm a pointer to the switch internal flow list
638 * @param in_gport ingress virtual port (LIF) this acl applied
639 * @return error code
640 */
641static bcmos_errno bal_sw_util_dpp_dft_acl_add(int unit, bcmbal_flow_cfg *p_flow, bal_sw_flow *p_flow_elm, uint32_t in_gport)
642{
643 bcmos_errno err;
644 bcm_field_entry_t dft_eid = 0;
645 int32_t ret = 0;
646
647 if(p_flow_elm->num_eid >= MAX_FIELD_EID)
648 {
649 BCM_LOG(ERROR, log_id_sw_util, "Too many dft ACL rules in flow id %d\n", p_flow_elm->id);
650 return BCM_ERR_NORES;
651 }
652
653 err = bal_sw_util_dpp_dft_fg_create(unit, &dpp_group_id);
654
655 if (BCM_ERR_ALREADY != err && BCM_ERR_OK != err)
656 {
657 BCM_LOG(ERROR, log_id_sw_util, "Field Default Group %d create failed\n", dpp_dft_group_id);
658 return err;
659 }
660 do
661 {
662 /* Install a default drop ACL at lowest priority(0).
663 This will drop unmatch packets received on the same ingress LIF
664 */
665
666 ret = bcm_field_entry_create(unit, dpp_group_id, &dft_eid);
667 if (ret)
668 {
669 BCM_LOG(ERROR, log_id_sw_util, "field_entry_create failed - %d\n", ret);
670 break;
671 }
672
673 /* add vPort to match rule */
674 ret = bcm_field_qualify_InVPort32(unit, dft_eid, in_gport, 0xffff);
675 if (ret)
676 {
677 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_InVPort failed - %d\n", ret);
678 break;
679 }
680
681 /* add Packet type to match rule, drop only unicast */
682 ret = bcm_field_qualify_PacketRes(unit, dft_eid, BCM_FIELD_PKT_RES_L2UC, 0);
683 if (ret)
684 {
685 BCM_LOG(ERROR, log_id_sw_util, "field_qualify_PacketRes failed - %d\n", ret);
686 break;
687 }
688
689
690 /* set to lowest priority 0 */
691 ret = bcm_field_entry_prio_set(unit, dft_eid, 0);
692 if (ret)
693 {
694 BCM_LOG(ERROR, log_id_sw_util, "field entry priority failed - %d\n", ret);
695 break;
696 };
697
698 /* Drop the packet */
699 ret = bcm_field_action_add(unit, dft_eid, bcmFieldActionDrop, 0, 0);
700 if (ret)
701 {
702 BCM_LOG(ERROR, log_id_sw_util, "field action add failed - %d\n", ret);
703 break;
704 };
705 ret = bcm_field_entry_install(unit, dft_eid);
706 if (ret)
707 {
708 BCM_LOG(ERROR, log_id_sw_util, "field_entry_install %d failed - %d\n", dft_eid, ret);
709 break;
710 }
711 else
712 {
713 BCM_LOG(INFO, log_id_sw_util, "Add default rule %d Success\n", dft_eid);
714 }
715 }while(0);
716 if (ret != BCM_E_NONE)
717 {
718 return BCM_ERR_INTERNAL;
719 }
720 else
721 {
722 p_flow_elm->field_entry_id[p_flow_elm->num_eid] = dft_eid;
723 p_flow_elm->num_eid += 1;
724 return BCM_ERR_OK;
725 }
726}
727
728/**
729 * @brief The ingress vlan translation function modified the packet VLAN tag
730 * before sending it out
731 *
732 * @param unit the switch unit this rule is to be added
733 * @param p_flow a pointer to the flow definition the created rule will be based on
734 * @param ingport the gport the translation will be applied
735 * @return error code
736 */
737static bcmos_errno bal_sw_util_dpp_invlanx(int unit, bcmbal_flow_cfg *p_flow, uint32_t ingport)
738{
739 int rv = 0;
740 bcm_vlan_action_set_t action;
741 bcm_vlan_action_set_t_init(&action);
742 bcmos_errno ret;
743
744 if(BCMBAL_ACTION_CMD_ID_IS_SET( &(p_flow->data.action), BCMBAL_ACTION_CMD_ID_REMARK_PBITS))
745 {
746 int qos_map_id, i_pri, o_pri;
747
748 do
749 {
750 switch(p_flow->data.classifier.pkt_tag_type)
751 {
752 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
753 /* should be
754 action.dt_outer_pkt_prio = bcmVlanActionReplace;
755 action.new_outer_vlan = p_flow->data.classifier.o_vid;;
756 action.dt_outer = bcmVlanActionReplace;
757 but it does not seems to work. Using ot_outer seems to also work for double tagged packets
758 */
759 action.ot_outer_pkt_prio = bcmVlanActionReplace;
760 action.new_outer_vlan = p_flow->data.classifier.o_vid;
761 action.ot_outer = bcmVlanActionReplace;
762 break;
763 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
764 action.ot_outer_pkt_prio = bcmVlanActionReplace;
765 action.new_outer_vlan = p_flow->data.classifier.o_vid;
766 action.ot_outer = bcmVlanActionReplace;
767
768 break;
769 default:
770 BCM_LOG(ERROR, log_id_sw_util,
771 "Error, pbits translation on untagged packets\n");
772 return BCM_ERR_NOT_SUPPORTED;
773 break;
774 }
775
776
777 /* perform o_pbits translation */
778 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_pbits))
779 {
780 i_pri = p_flow->data.classifier.o_pbits;
781 }
782 else
783 {
784 /* mark the source pcp DONTCARE */
785 i_pri = -1;
786 }
787 /* flow validation already make sure the action.o_pbits is set for REMARK_PBITS */
788 o_pri = p_flow->data.action.o_pbits;
789
790 ret = bal_sw_dpp_pcp_remark_map_get(i_pri, o_pri, &qos_map_id);
791
792 if (ret != BCM_ERR_OK)
793 {
794 BCM_LOG(ERROR, log_id_sw_util,
795 "Error, faile to obtain pcp map id, ret = %d\n", ret);
796 rv = BCM_E_UNAVAIL;
797 break;
798 }
799
800 rv = bcm_qos_port_map_set(unit, ingport, qos_map_id, -1);
801 if (rv != BCM_E_NONE)
802 {
803 BCM_LOG(ERROR, log_id_sw_util,
804 "Error, pbits translation bcm_qos_port_map_set ret = %d\n", rv);
805 break;
806 }
807
808 /* set the action priority profile */
809 action.priority = qos_map_id;
810 action.new_inner_pkt_prio = qos_map_id;
811 }while(0);
812 }
813 else
814 {
815 /* nothing to do, return OK */
816 return BCM_ERR_OK;
817 }
818 if(rv != BCM_E_NONE)
819 {
820 return BCM_ERR_INTERNAL;
821 }
822
823 rv = bcm_vlan_translate_action_create(unit, ingport, bcmVlanTranslateKeyPortOuter, BCM_VLAN_INVALID, BCM_VLAN_NONE, &action);
824 if( rv )
825 {
826 return BCM_ERR_INTERNAL;
827 }
828 else
829 {
830 BCM_LOG(INFO, log_id_sw_util, "Perform ingress vlan translation w %s action on gport 0x%x\n",
831 (p_flow->data.classifier.pkt_tag_type == BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG)? "DT": "ST",
832 ingport);
833 return BCM_ERR_OK;
834 }
835}
836/**
837 * @brief The egress vlan translation function modified the packet VLAN tag
838 * before sending it out
839 *
840 * @param unit the switch unit this rule is to be added
841 * @param p_flow a pointer to the flow definition the created rule will be based on
842 * @param egport the gport the translation will be applied
843 * @return error code
844 */
845static bcmos_errno bal_sw_util_dpp_evlanx(int unit, bcmbal_flow_cfg *p_flow, uint32_t egport)
846{
847 int rv = 0;
848 bcm_vlan_action_set_t action;
849 bcm_vlan_action_set_t_init(&action);
850
851 if(BCMBAL_ACTION_CMD_ID_IS_SET( &(p_flow->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG))
852 {
853 action.new_outer_vlan = p_flow->data.action.o_vid;
854 action.priority = 0;
855 switch(p_flow->data.classifier.pkt_tag_type)
856 {
857 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
858 action.ut_outer = bcmVlanActionAdd;
859 action.ut_outer_pkt_prio = bcmVlanActionAdd;
860 break;
861 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
862 action.ot_outer = bcmVlanActionAdd;
863 action.ot_outer_pkt_prio = bcmVlanActionAdd;
864 break;
865 default:
866 action.new_outer_vlan = 0;
867 action.ot_outer = bcmVlanActionNone;
868 break;
869 }
870
871 if( p_flow->data.action.o_tpid )
872 {
873 action.outer_tpid_action = bcmVlanTpidActionModify;
874 action.outer_tpid = p_flow->data.action.o_tpid;
875 }
876
877 }
878 else if(BCMBAL_ACTION_CMD_ID_IS_SET( &(p_flow->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG))
879 {
880 switch(p_flow->data.classifier.pkt_tag_type)
881 {
882 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
883 /* should be action.dt_outer = bcmVlanActionDelete,
884 but it does not seems to work. Using ot_outer seems to also work for double tagged packets */
885 action.ot_outer = bcmVlanActionDelete;
886 break;
887 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
888 action.ot_outer = bcmVlanActionDelete;
889 break;
890 default:
891 action.ut_outer = bcmVlanActionNone;
892 break;
893 }
894 }
895 else if (BCMBAL_ACTION_CMD_ID_IS_SET( &(p_flow->data.action), BCMBAL_ACTION_CMD_ID_XLATE_OUTER_TAG))
896 {
897 action.new_outer_vlan = p_flow->data.action.o_vid;
898 switch(p_flow->data.classifier.pkt_tag_type)
899 {
900 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
901 /* should be action.dt_outer = bcmVlanActionReplace,
902 but it does not seems to work. Using ot_outer seems to also work for double tagged packets */
903 action.ot_outer = bcmVlanActionReplace;
904 break;
905 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
906 action.ot_outer = bcmVlanActionReplace;
907 break;
908 default:
909 action.ut_outer = bcmVlanActionNone;
910 break;
911 }
912
913 /** @todo tpid is not translated for now */
914 /** @note the vid translated from is passed as a parameter to the api call */
915
916 }
917 else
918 {
919 /* nothing to do, return OK */
920 return BCM_ERR_OK;
921 }
922
923 rv = bcm_vlan_translate_egress_action_add(unit, egport, BCM_VLAN_NONE, BCM_VLAN_NONE, &action);
924 if( rv )
925 {
926 BCM_LOG(ERROR, log_id_sw_util, "bcm_vlan_translate_egress_action_add failed %d on gport 0x%x\n", rv, egport);
927 return BCM_ERR_INTERNAL;
928 }
929 else
930 {
931 BCM_LOG(INFO, log_id_sw_util, "Perform egress vlan translation on gport 0x%x\n", egport);
932 return BCM_ERR_OK;
933 }
934}
935/**
936 * @brief Multicast flow add function forward the specified multicast packets to a multicast group.
937 * The multicast group has to be created prio to the mc_flow add operation
938 *
939 * @param p_flow a pointer to the flow definition the created rule will be based on
940 * @param service_type id this multicast flow is for multicast or downstream N:1 service
941 * @return error code
942 */
943static bcmos_errno bal_sw_util_dpp_mc_flow_add(bcmbal_flow_cfg *p_flow, uint32_t service_type)
944{
945 bcmos_errno ret = BCM_ERR_OK;
946 bcm_gport_t nni_gport;
947 int ii, unit, rv;
948 int nni;
949 bcm_vlan_t vsi;
950 bal_sw_flow *p_flow_elm;
951 bal_sw_flow flow_elm;
952 bal_sw_vsi_service *p_vsi_svc;
953 bal_sw_group_list *p_group_list;
954 uint32_t svc_tag_indx;
955
956 /* get a pointer to the specified group instance */
957 p_group_list = bal_sw_util_dpp_group_list_get_by_id(p_flow->data.group_id);
958
959 if ( p_group_list == NULL)
960 {
961 BCM_LOG(ERROR, log_id_sw_util,
962 " ERROR: group %d not found\n", p_flow->data.group_id);
963 return BCM_ERR_INTERNAL;
964 }
965
966 unit = p_group_list->device;
967
968 /* make sure this flow id does not already exist */
969 p_flow_elm = bal_sw_util_flow_list_get_by_id(p_flow->key.flow_id);
970 if (p_flow_elm)
971 {
972 BCM_LOG(ERROR, log_id_sw_util,
973 " ERROR: flow id %d type %d already exist\n",p_flow->key.flow_id, p_flow->key.flow_type);
974 return BCM_ERR_INTERNAL;
975 }
976
977 do
978 {
979 /* initialize link list flow element */
980 memset(&flow_elm, 0, sizeof (bal_sw_flow));
981 /* fill in the basic info */
982 flow_elm.id = p_flow->key.flow_id;
983 flow_elm.device = unit;
984 flow_elm.group_id = p_flow->data.group_id;
985 flow_elm.flow_cookie = p_flow->data.cookie;
986
987 /* packet tag type are required fields when create NNI LIF */
988 /* Here make sure it is the supported type */
989 if(p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_UNTAGGED &&
990 p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_SINGLE_TAG &&
991 p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG)
992 {
993 BCM_LOG(ERROR, log_id_sw_util,
994 " ERROR: MC classifier packet tag type 0x%x is invalid\n", p_flow->data.classifier.pkt_tag_type);
995 ret = BCM_ERR_PARM;
996 break;
997 }
998
999 /* retrieve the vswitch instance */
1000 p_vsi_svc = p_group_list->p_vsi;
1001 if(p_vsi_svc == NULL)
1002 {
1003 BCM_LOG(ERROR, log_id_sw_util, "Error, MC: vsi not created\n");
1004 ret = BCM_ERR_INTERNAL;
1005 break;
1006 }
1007 vsi = p_vsi_svc->vswitch;
1008
1009 /* add flow to the vsi service tag list */
1010 ret = bal_sw_util_dpp_vsi_service_tag_add(unit, p_vsi_svc, p_flow, &svc_tag_indx);
1011 if (ret != BCM_ERR_OK)
1012 {
1013 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add flow to vsi service tag list\n");
1014 break;
1015 }
1016
1017 ii = 0; /* Start with the first NNI logical interface */
1018 /* loop through all nni port, add them to vswitch, -1 indicate end of table */
1019 /* Configure the switch nni LIF based on classifier in the flow. */
1020 while(-1 != (nni = bal_bcm_net_inf_pbm_get(ii)))
1021 {
1022 /* skip nni port that is not in the same device or not valid */
1023 if ( bal_bcm_net_inf_dev_get(ii) != unit ||
1024 BCMOS_FALSE == bcm_topo_nni_is_valid(ii))
1025 {
1026 ii++;
1027 continue;
1028 }
1029
1030 /* if nni port is specified in the flow, skip the other nni ports */
1031 if ( BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id) &&
1032 ii != p_flow->data.network_int_id
1033 )
1034 {
1035 ii++;
1036 continue;
1037 }
1038
1039 /* create gport based on nni physical port number */
1040 ret = bal_sw_util_dpp_vsi_service_port_add(unit, p_vsi_svc, svc_tag_indx, nni, &nni_gport);
1041 if (ret != BCM_ERR_OK)
1042 {
1043 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add nni %d to vsi\n", nni);
1044 break;
1045 }
1046
1047 /* if DMAC is set, create a L2 entry, otherwise flood unknown to the group */
1048 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_mac))
1049 {
1050 /* add static MC 01:00:5E:00:00:start_mc to the dowstream MC group */
1051 bcm_l2_addr_t l2addr;
1052 bcm_mac_t mc_mac;
1053
1054 /* Add mc mac address */
1055 memcpy(&mc_mac, &(p_flow->data.classifier.dst_mac), sizeof(bcm_mac_t));
1056
1057 bcm_l2_addr_t_init(&l2addr, mc_mac, vsi);
1058 l2addr.flags = BCM_L2_STATIC | BCM_L2_MCAST;
1059 /* direct output to the MC group */
1060 l2addr.l2mc_group = p_group_list->l2_grp_id;
1061
1062 rv = bcm_l2_addr_add(unit, &l2addr);
1063 if (rv != BCM_E_NONE)
1064 {
1065 BCM_LOG(ERROR, log_id_sw_util,"Error: bcm_l2_addr_add MC returned %s \n",
1066 bcm_errmsg(rv));
1067 ret = BCM_ERR_INTERNAL;
1068 break;
1069 }
1070 }
1071 else
1072 {
1073 rv = bcm_port_control_set(unit, nni_gport, bcmPortControlFloodUnknownMcastGroup, BAL_DPP_MC_OFFSET);
1074 if (rv != BCM_E_NONE)
1075 {
1076 BCM_LOG(ERROR, log_id_sw_util, "Error, MC: bcm_port_control_set for nni failed %d\n", rv);
1077 ret = BCM_ERR_INTERNAL;
1078 break;
1079 }
1080 }
1081
1082 flow_elm.num_net++;
1083 flow_elm.net_port[ii] = nni_gport;
1084
1085 ii++; /* Next NNI */
1086 }
1087 /* skip the rest if anything goes wrong */
1088 if( ret != BCM_ERR_OK)
1089 {
1090 break;
1091 }
1092 /* perform vlan translation on nni port */
1093 if (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action))
1094 {
1095 BCM_LOG(WARNING, log_id_sw_util, "Warning, action for multicast flow not supported\n");
1096 }
1097
1098 } while(0);
1099
1100 if( ret == BCM_ERR_OK)
1101 {
1102 /* increase the group reference count */
1103 p_group_list->use_count++;
1104 /* increase the vsi reference count */
1105 p_vsi_svc->use_count++;
1106 /* add the flow info to the flow link list */
1107 flow_elm.p_vsi_svc = p_vsi_svc;
1108 flow_elm.num_pon = 0;
1109 flow_elm.type = service_type;
1110 /* nni ports are done in the nni loop */
1111 flow_elm.valid = 1;
1112 bal_sw_util_flow_list_insert(flow_elm);
1113
1114 BCM_LOG(INFO, log_id_sw_util, "Add flow_elm %d type %d, vswitch 0x%x, group_id %d Success\n", flow_elm.id, flow_elm.type, p_vsi_svc->vswitch, flow_elm.group_id);
1115 }
1116 return ret;
1117}
1118
1119/* HW limitation on max burst rate - bps */
1120#define BAL_MAX_BURST_RATE (1 << 16)
1121
1122/**
1123 * @brief The flow add function program DPP to forward packets that have
1124 * specified attributes to the designated ports.
1125 * The packets is modified before egress
1126 * In case IWF is in DIRECT MODE,
1127 * On the downstream, a tunnel id (outer vlan tag) is added to the packets
1128 * On the upstream, outer vlan tag (tunnel id) is removed from the packets
1129 * In case IWF is in PER_FLOW_MODE, currently not supported
1130 *
1131 * @note a flow can be created which does VID translation between V & U (refer to TR156) interfaces.
1132 *
1133 * @note This routine adds flow for both upstream and downstream direction i.e. create PON & NNI LIFs
1134 * for both directions in a same call to this routine - and all this as part of a single call to this function
1135 * from the application module or CLI.
1136 * It also programs the egress vlan translation modules for both upstream and downstream.
1137 *
1138 * @note The general sequence is:
1139 * \li create PON LIF with matching ingress tunnel id (and vlan id, if upstream pkts are vlan tagged)
1140 * \li next, configure egress vlan translation on PON side (for downstream pkts)
1141 * \li create NNI LIF with matching ingress vlan id (currently by default it assumes downstream packets are tagged)
1142 * \li next, configure egress vlan translation on NNI side (for upstream pkts)
1143 *
1144 * @param iwf_mode The InterWorking Function mode - DIRECT or PER-FLOW
1145 * @param p_flow A pointer to the requested add flow info
1146 * @return error code
1147 */
1148bcmos_errno bal_sw_util_dpp_flow_add(bcmbal_iwf_mode iwf_mode, bcmbal_flow_cfg *p_flow)
1149{
1150 bcmos_errno ret = BCM_ERR_OK;
1151 bcm_gport_t pon_gport, nni_gport;
1152 bcm_vlan_t tunnel_id;
1153 int ii, unit, rv;
1154 bcm_vlan_port_t vp;
1155 int pon, nni, sys_pon;
1156 bcm_vlan_t vsi;
1157 int pon_encap_id;
1158 bal_sw_flow *p_flow_elm;
1159 uint32_t flow_type, max_burst, svc_tag_indx;
1160 bal_sw_flow flow_elm;
1161 bal_sw_dpp_qos_service_cfg *p_service_cfg = NULL;
1162 bcmbal_flow_cfg flow_rev; /* used for configuration in opposite direction */
1163 bcmbal_flow_cfg *p_us_flow, *p_ds_flow;
1164 bal_sw_vsi_service *p_vsi_svc;
1165
1166 BCM_LOG(INFO, log_id_sw_util,
1167 " Got an DPP flow request - iwf_mode=%d flow_id=%d flow_type=%d, sub_port=%d svc_id=%d\n",
1168 iwf_mode,
1169 p_flow->key.flow_id, p_flow->key.flow_type, p_flow->data.access_int_id, p_flow->data.svc_port_id);
1170 BCM_LOG(DEBUG, log_id_sw_util,
1171 " classifier - mask=0x%x otpid=%x itpid=%x ovid=%x ivid=%x\n",
1172 p_flow->data.classifier.presence_mask,
1173 p_flow->data.classifier.o_tpid, p_flow->data.classifier.i_tpid,
1174 p_flow->data.classifier.o_vid, p_flow->data.classifier.i_vid);
1175
1176
1177 if ( iwf_mode != BCMBAL_IWF_MODE_DIRECT_MAPPING)
1178 {
1179 BCM_LOG(ERROR, log_id_sw_util,
1180 " ERROR: not supported IWF mode - %d\n", iwf_mode);
1181 return BCM_ERR_NOT_SUPPORTED;
1182 }
1183
1184 if (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action))
1185 {
1186 BCM_LOG(DEBUG, log_id_sw_util,
1187 " action.params: .cmds_bitmask=0x%x, .input_pkt_tag_type=0x%x\n",
1188 p_flow->data.action.cmds_bitmask,
1189 p_flow->data.classifier.pkt_tag_type);
1190 }
1191
1192 if (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
1193 BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, sla) &&
1194 p_flow->data.sla.max_rate < p_flow->data.sla.min_rate)
1195 {
1196 BCM_LOG(ERROR, log_id_sw_util,
1197 " ERROR: Max rate %d kbps is not >= Min rate %d kbps\n", p_flow->data.sla.max_rate, p_flow->data.sla.min_rate );
1198 return BCM_ERR_NOT_SUPPORTED;
1199 }
1200
1201 switch(p_flow->key.flow_type)
1202 {
1203 case BCMBAL_FLOW_TYPE_DOWNSTREAM:
1204 flow_type = BAL_SW_FLOW_TYPE_DOWNSTREAM;
1205 /* for downstream N:1 service, same flood settings as multicast flow */
1206 if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, group_id))
1207 {
1208 return bal_sw_util_dpp_mc_flow_add(p_flow, BAL_SW_FLOW_TYPE_DOWNSTREAM);
1209 }
1210 break;
1211 case BCMBAL_FLOW_TYPE_UPSTREAM:
1212 flow_type = BAL_SW_FLOW_TYPE_UPSTREAM;
1213 break;
1214 case BCMBAL_FLOW_TYPE_MULTICAST:
1215 return bal_sw_util_dpp_mc_flow_add(p_flow, BCMBAL_FLOW_TYPE_MULTICAST);
1216 default:
1217 return BCM_ERR_NOT_SUPPORTED;
1218 }
1219
1220 unit = bal_bcm_pon_inf_dev_get(p_flow->data.access_int_id);
1221 /* We program a flow with 3 switch components, inLIF, vSwitch and outLIF.
1222 LIF is always bi-directional operation, so for uni-directional flow we programmed an ingress or egress DROP
1223 on PON based on the BAL flow direction. Later, when the BAL flow from the other direction is SET, we
1224 remove the DROP from the PON.
1225 This imply that two BAL flows with same id must have symmetry vlan manipulation operations.
1226 */
1227 p_flow_elm = bal_sw_util_flow_list_get_by_id(p_flow->key.flow_id);
1228 if (p_flow_elm)
1229 {
1230 /* Check if flow with same id and type exist or not.
1231 If downstream exist, remove the DISCARD_INGRESS from PON port by set it to DISCARD_NONE.
1232 If upstream exist, remove the DISCARD_EGRESS from PON port by set it to DISCARD_NONE.
1233 Asymmetry operations need two flows with different ID - each flow in uni-direction */
1234 if(!(p_flow_elm->type & flow_type))
1235 {
1236 bcmbal_flow_cfg *p_ref_flow = NULL;
1237 bcmbal_flow_key key;
1238 /* retrieve the classifier on the other flow direction */
1239 key.flow_id = p_flow->key.flow_id;
1240 key.flow_type = (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM)? BCMBAL_FLOW_TYPE_UPSTREAM : BCMBAL_FLOW_TYPE_DOWNSTREAM;
1241 p_ref_flow = flow_get_current_info_by_key(key);
1242 if(NULL == p_ref_flow)
1243 {
1244 BCM_LOG(ERROR, log_id_sw_util,
1245 " ERROR: Can't locate flow %d type %d info from main DB\n", key.flow_id, key.flow_type);
1246 return BCM_ERR_INTERNAL;
1247 }
1248 /* check the symmetrical properties between two flows */
1249 if (BCMOS_FALSE == bal_sw_util_is_symmetry_flows(p_flow, p_ref_flow))
1250 {
1251 BCM_LOG(ERROR, log_id_sw_util,
1252 " ERROR: Flow %d does not have symmetry classifiers\n", key.flow_id);
1253 return BCM_ERR_INTERNAL;
1254 }
1255
1256 /* if there is SLA in downstream, remove the US flow ( LIFs & VSWITCH) and build a new bi-direction flow.
1257 This is because LIF is always bi-directional and when the US flow is created the PON LIF has no downstream VOQ.
1258 One needs to create a new PON LIF with VOQ for SLA. There is no easy way to add VOQ to an existing LIF. */
1259 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
1260 BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, sla) )
1261 {
1262 /* remove the existing US flow */
1263 ret = bal_sw_util_dpp_flow_remove_int(p_flow_elm);
1264 if(ret != BCM_ERR_OK)
1265 {
1266 BCM_LOG(ERROR, log_id_sw_util,
1267 " ERROR: fail to remove flow %d from the list\n", p_flow->key.flow_id);
1268
1269 return BCM_ERR_INTERNAL;
1270 }
1271 flow_type = BAL_SW_FLOW_TYPE_DOWNSTREAM | BAL_SW_FLOW_TYPE_UPSTREAM;
1272 /* goto regular path to create bi-directional flow */
1273 }
1274 /* if no SLA and the classifier is more than just port + VLAN tags, add ACL rule to re-direct packet to egress port.
1275 This bypass the ingress LIF as LIF check VID only.
1276 Upstream classification is expected to be done in ONU (onu add GEM based on classifiers for upstream),
1277 return success after complete as there is no other changes needed for existing flow.
1278 */
1279 else
1280 {
1281 int i;
1282 bcmos_bool is_nni_set = BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id);
1283
1284 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
1285 bal_sw_util_flow_ds_acl_cls_chk(p_flow) == BCMOS_TRUE )
1286 {
1287 for(i=0; i < p_flow_elm->num_pon; i++)
1288 {
1289 for(ii=0; ii < p_flow_elm->num_net; ii++)
1290 {
1291 /*first get the ING logical port from gport */
1292 bcm_vlan_port_t tmp_vp;
1293 bcm_vlan_port_t_init(&tmp_vp);
1294 tmp_vp.vlan_port_id = p_flow_elm->net_port[ii];
1295 ret = bcm_vlan_port_find(unit, &tmp_vp);
1296 if(ret != BCM_ERR_OK)
1297 {
1298 BCM_LOG(WARNING, log_id_sw_util,
1299 " Warning: fail to retrieve logical port from gport 0x%x\n", p_flow_elm->net_port[ii]);
1300 continue;
1301 }
1302 /* if nni port is specified in the flow, skip the other nni ports */
1303 if ( BCMOS_TRUE == is_nni_set && tmp_vp.port != bal_bcm_net_inf_pbm_get(p_flow->data.network_int_id))
1304 {
1305 ii++;
1306 /* if nni is set, it has to be in the nni list of the opposit FLOW */
1307 /* set the return to BCM_ERR_INTERNAL, in case it reach the end of for-loop. */
1308 ret = BCM_ERR_INTERNAL;
1309 continue;
1310 }
1311 /* Rule need to match the ingress port, otherwise, it will apply to all ports - nni and pon */
1312 if ( BCMOS_TRUE != is_nni_set)
1313 {
1314 BCMBAL_CFG_PROP_SET(p_flow, flow, network_int_id, bal_bcm_net_inf_idx_get(tmp_vp.port));
1315 }
1316 ret = bal_sw_util_dpp_acl_add(unit, p_flow, p_flow_elm, p_flow_elm->net_port[ii], p_flow_elm->pon_port[i]);
1317 if ( BCMOS_TRUE != is_nni_set)
1318 {
1319 BCMBAL_CFG_PROP_CLEAR(p_flow, flow, network_int_id);
1320 }
1321 if (ret != BCM_ERR_OK)
1322 {
1323 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add forwarding acl on nni %d, ret = %d\n", ret, ii);
1324 break;
1325 }
1326 /* add a dft drop rule (priority 0) on the LIF to drop packets that match VID but no match for other fields */
1327 ret = bal_sw_util_dpp_dft_acl_add(unit, p_flow, p_flow_elm, p_flow_elm->net_port[ii]);
1328 if (ret != BCM_ERR_OK)
1329 {
1330 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add default acl on nni=0x%x, ret = %d\n", p_flow_elm->net_port[ii], ret);
1331 break;
1332 }
1333 }
1334 if (ret != BCM_ERR_OK)
1335 {
1336 break;
1337 }
1338 }
1339
1340 if(ret != BCM_ERR_OK)
1341 {
1342 BCM_LOG(ERROR, log_id_sw_util,
1343 " ERROR: fail to add DS ACL to nni_%d in flow id %d from the list\n", ii,p_flow->key.flow_id);
1344
1345 return BCM_ERR_INTERNAL;
1346 }
1347 }
1348 /* If the US and DS has asymmetrical nature, we only program common part (VID) when create the LIF
1349 We need an ACL rule to perform upstream specific classification and forwarding.
1350 In addition, ACL allow upstream flows to be prioritized based on priority field.*/
1351 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM &&
1352 bal_sw_util_flow_us_acl_cls_chk(p_flow) == BCMOS_TRUE &&
1353 /* there are issues using traditional API for PON application when egress vlan translation and ingress ACL are both active.
1354 Enable the ACL only when there is no vlan action - TBD */
1355 BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action))
1356 {
1357 if ( BCMOS_FALSE == is_nni_set)
1358 {
1359 BCM_LOG(ERROR, log_id_sw_util,
1360 " ERROR: Upstream classifier in addition to VID without setting NNI is not supported\n");
1361 return BCM_ERR_INTERNAL;
1362 }
1363
1364 for(i=0; i < p_flow_elm->num_pon; i++)
1365 {
1366 ret = bal_sw_util_dpp_acl_add(unit, p_flow, p_flow_elm, p_flow_elm->pon_port[i], p_flow_elm->net_port[p_flow->data.network_int_id]);
1367
1368 if (ret != BCM_ERR_OK)
1369 {
1370 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add forwarding acl on pon %d, ret = %d\n", ret, i);
1371 break;
1372 }
1373 /* add a default drop rule (priority 0) on the LIF to drop packets that match VID but no match for other fields */
1374 ret = bal_sw_util_dpp_dft_acl_add(unit, p_flow, p_flow_elm, p_flow_elm->pon_port[i]);
1375 if (ret != BCM_ERR_OK)
1376 {
1377 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add default acl on pon=0x%x, ret = %d\n", p_flow_elm->pon_port[i], ret);
1378 break;
1379 }
1380 }
1381
1382 if(ret != BCM_ERR_OK)
1383 {
1384 BCM_LOG(ERROR, log_id_sw_util,
1385 " ERROR: fail to add US ACL to pon_%d in flow id %d from the list\n", i, p_flow->key.flow_id);
1386 return BCM_ERR_INTERNAL;
1387 }
1388 }
1389
1390 BCM_LOG(INFO, log_id_sw_util,
1391 " remove packet discard function from PON in flow id %d \n",p_flow->key.flow_id);
1392 /* remove the PON ports from DISCARD_XXX mode */
1393 for(ii=0; ii<p_flow_elm->num_pon; ii++)
1394 {
1395 if(p_flow_elm->pon_port[ii] == 0)
1396 {
1397 /* if PON LIF is deleted, then continue to the next one */
1398 continue;
1399 }
1400 ret = bcm_port_discard_set(p_flow_elm->device, p_flow_elm->pon_port[ii], BCM_PORT_DISCARD_NONE);
1401 if (ret != BCM_ERR_OK)
1402 {
1403 break;
1404 }
1405 }
1406 if(ret != BCM_ERR_OK)
1407 {
1408 BCM_LOG(ERROR, log_id_sw_util,
1409 " ERROR: fail to remove packet discard from pon_%d in flow id %d from the list\n", ii,p_flow->key.flow_id);
1410
1411 ret = BCM_ERR_INTERNAL;
1412 }
1413 else
1414 {
1415 /* add flow type to the exist list */
1416 p_flow_elm->type |= flow_type;
1417 ret = BCM_ERR_OK;
1418 }
1419 return ret;
1420 }
1421 }
1422 else /* same id and type is an error - we do not check if contents are the same or not */
1423 {
1424 BCM_LOG(ERROR, log_id_sw_util,
1425 " ERROR: flow id %d type %d already exist\n",p_flow->key.flow_id, p_flow->key.flow_type);
1426 return BCM_ERR_INTERNAL;
1427 }
1428 }
1429
1430 /*
1431 * First, validate that the specified PON has at least one NNI port on the same device.
1432 * If not, return an error, as this is not supported.
1433 */
1434 ii = 0;
1435 ret = BCM_ERR_NOT_SUPPORTED;
1436 /* walk through the entire mapping table */
1437 while(-1 != bal_bcm_net_inf_pbm_get(ii))
1438 {
1439 if(bal_bcm_net_inf_dev_get(ii) == unit)
1440 {
1441 ret = BCM_ERR_OK;
1442 break;
1443 }
1444 ii++; /* Next NNI */
1445 }
1446
1447 do
1448 {
1449 /*
1450 * Check return code from device check above. Return if there was no local PON .
1451 */
1452 if(BCM_ERR_OK != ret)
1453 {
1454 BCM_LOG(ERROR, log_id_sw_util,
1455 " ERROR: no network port is on the same device as access port %d\n", p_flow->data.access_int_id);
1456 break;
1457 }
1458
1459 /* initialize link list flow element */
1460 memset(&flow_elm, 0, sizeof (bal_sw_flow));
1461 /* fill in the basic info */
1462 flow_elm.id = p_flow->key.flow_id;
1463 flow_elm.device = unit;
1464 flow_elm.type = flow_type;
1465 flow_elm.svc_port = p_flow->data.svc_port_id;
1466 flow_elm.flow_cookie = p_flow->data.cookie;
1467
1468 tunnel_id = (bcm_vlan_t)p_flow->data.svc_port_id;
1469 pon = bal_bcm_pon_inf_pbm_get(p_flow->data.access_int_id);
1470
1471 /* Map the tunnel ID to a PON channel OTM port */
1472 rv = bcm_port_pon_tunnel_map_set(unit,
1473 pon,
1474 tunnel_id,
1475 pon);
1476 if (rv != BCM_E_NONE)
1477 {
1478 BCM_LOG(ERROR, log_id_sw_util,
1479 "Error, bcm_port_pon_tunnel_map_set on pon %d failed %d"
1480 " (have you chosen the correct intf_maptable?)\n", pon, rv);
1481 ret = BCM_ERR_INTERNAL;
1482 break;
1483 }
1484
1485 /* For TRAP to HOST action, it can be either upstream or downsteram,
1486 There is no packet manipulation, just insert an ACL and return.
1487 For flow action equal TRAP_TO_HOST, DS flow has to use different flow id even if the classifier is the same as the US.
1488 This is to simplify the REMOVE/DELETE operation in the switch.
1489 */
1490 if ((BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action)) &&
1491 (p_flow->data.action.cmds_bitmask & BCMBAL_ACTION_CMD_ID_TRAP_TO_HOST)
1492 )
1493 {
1494 /* For US, create an in LIF for matching, this allow trapping of different tunnel_id on the same PON.
1495 Tunnel_id is stripped before packets are forwarding to the host */
1496 if(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)
1497 {
1498 if(BCMOS_FALSE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type))
1499 {
1500 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow->data.classifier, classifier, pkt_tag_type, BCMBAL_PKT_TAG_TYPE_UNTAGGED);
1501 BCM_LOG(WARNING, log_id_sw_util, "Tag Type for Upstream Packet Trapping is not set, default to UNTAGGED\n");
1502 }
1503
1504 bcm_vlan_port_t_init(&vp);
1505
1506 /* preserve any incoming packet vlan tags */
1507 vp.flags = BCM_VLAN_PORT_OUTER_VLAN_PRESERVE | BCM_VLAN_PORT_INNER_VLAN_PRESERVE | BCM_VLAN_PORT_FORWARD_GROUP;
1508
1509 switch(p_flow->data.classifier.pkt_tag_type)
1510 {
1511 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
1512 /* match both tunnel and outer tag on ingress PON */
1513 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_VLAN;
1514 break;
1515 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
1516 /* match tunnel and both outer and inner tags on ingress PON */
1517 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_VLAN_STACKED;
1518 break;
1519 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
1520 default: /* just to make compiler happy */
1521 /* match tunnel tag on ingress PON */
1522 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL;
1523 break;
1524 }
1525
1526 vp.port = pon;
1527 vp.match_tunnel_value = tunnel_id;
1528 vp.egress_tunnel_value = tunnel_id;
1529 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid))
1530 {
1531 vp.match_vlan = p_flow->data.classifier.o_vid;
1532 }
1533 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid))
1534 {
1535 vp.match_inner_vlan = p_flow->data.classifier.i_vid;
1536 }
1537 vp.vsi = 0; /* will be populated when the gport is added to service, using vswitch_port_add */
1538
1539 /* Create the vlan port (i.e., PON LIF) */
1540 rv = bcm_vlan_port_create(unit, &vp);
1541 if (rv != BCM_E_NONE)
1542 {
1543 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_vlan_port_create pon %d failed %d\n", pon, rv);
1544 return BCM_ERR_INTERNAL;
1545 }
1546 ret = bal_sw_util_dpp_acl_add(unit, p_flow, &flow_elm, vp.vlan_port_id, 0);
1547 }
1548 else
1549 {
1550 ret = bal_sw_util_dpp_acl_add(unit, p_flow, &flow_elm, 0, 0);
1551 }
1552
1553 if(BCM_ERR_OK != ret)
1554 {
1555 BCM_LOG(ERROR, log_id_sw_util, " ERROR: fail to add %s acl rule on trap\n", (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)? "US":"DS" );
1556 }
1557 else
1558 {
1559 ret = bal_sw_util_flow_list_insert(flow_elm);
1560 BCM_LOG(INFO, log_id_sw_util, "Add flow_elm %d type %d, trap_code 0x%x, eid=%d Success\n", flow_elm.id, flow_elm.type, flow_elm.trap_code, flow_elm.field_entry_id[0]);
1561 }
1562 return ret;
1563 } /* endif TRAP_TO_HOST ACTION */
1564
1565 /* For TR-156 1:1, single tagged on V and R/S interface.
1566 The vswitch will push a tunnel tag on the down stream packets.
1567 The vswitch will pop the tunnel tag from the upstream packets.
1568
1569 TBD For TR-156 1:1, double tagged on V interface and single tagged on R/S interface.
1570 The vswitch will replace the outer tag with tunnel tag on the down stream packets.
1571 The vswitch will replace the tunnel tag with outer vid on upstream packets.
1572
1573 For TR-156 N:1, single tagged on V and R/S interface.
1574 The vswitch will learn the upstream source MAC for downstream forwarding
1575 */
1576
1577 /* packet tag type and service port id are required fields when there is no action - checked in validation stage */
1578 /* Here make sure it is the supported type */
1579 if(p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_UNTAGGED &&
1580 p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_SINGLE_TAG &&
1581 p_flow->data.classifier.pkt_tag_type != BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG)
1582 {
1583 BCM_LOG(ERROR, log_id_sw_util,
1584 " ERROR: classifier packet tag type 0x%x is invalid\n", p_flow->data.classifier.pkt_tag_type);
1585 ret = BCM_ERR_PARM;
1586 break;
1587 }
1588
1589 /* create a local reverse flow for symmetry configurations */
1590 ret = bal_sw_util_reverse_flow_create(p_flow, &flow_rev);
1591 if (ret != BCM_ERR_OK)
1592 {
1593 BCM_LOG(ERROR, log_id_sw_util, "Error, (internal failure): fail to reverse flow\n");
1594 ret = BCM_ERR_INTERNAL;
1595 break;
1596 }
1597
1598 if(p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)
1599 {
1600 p_us_flow = p_flow;
1601 p_ds_flow = &flow_rev;
1602 }
1603 else
1604 {
1605 p_us_flow = &flow_rev;
1606 p_ds_flow = p_flow;
1607 }
1608
1609
1610 /* create the vswitch */
1611 /* if flow is associated with a GROUP, use the vswitch from the GROUP */
1612 if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, group_id))
1613 {
1614 bal_sw_group_list *p_group_list;
1615 /* get a pointer to the specified group instance */
1616 p_group_list = bal_sw_util_dpp_group_list_get_by_id(p_flow->data.group_id);
1617
1618 if ( p_group_list == NULL)
1619 {
1620 BCM_LOG(ERROR, log_id_sw_util,
1621 " ERROR: group %d not found\n", p_flow->data.group_id);
1622 ret = BCM_ERR_INTERNAL;
1623 break;
1624 }
1625
1626 /* retrieve the vswitch instance */
1627 p_vsi_svc = p_group_list->p_vsi;
1628 vsi = (p_group_list->p_vsi)->vswitch;
1629 /* add flow to the vsi service tag list */
1630 ret = bal_sw_util_dpp_vsi_service_tag_add(unit, p_vsi_svc, p_flow, &svc_tag_indx);
1631 if (ret != BCM_ERR_OK)
1632 {
1633 BCM_LOG(ERROR, log_id_sw_util, "Error, flow fail to add service to vsi service tag list\n");
1634 ret = BCM_ERR_INTERNAL;
1635 break;
1636 }
1637
1638 /* set the mac learning distribution list */
1639 if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, resolve_mac) &&
1640 BCMOS_TRUE == p_flow->data.resolve_mac)
1641 {
1642 bcm_l2_addr_distribute_t dist;
1643
1644 bcm_l2_addr_distribute_t_init(&dist);
1645 dist.vid = vsi;
1646 dist.flags = BCM_L2_ADDR_DIST_SET_CPU_DMA_DISTRIBUTER | BCM_L2_ADDR_DIST_SET_LEARN_DISTRIBUTER;
1647 dist.flags |= BCM_L2_ADDR_DIST_LEARN_EVENT | BCM_L2_ADDR_DIST_AGED_OUT_EVENT | BCM_L2_ADDR_DIST_STATION_MOVE_EVENT;
1648 rv = bcm_l2_addr_msg_distribute_set(unit, &dist);
1649 if (rv != BCM_E_NONE)
1650 {
1651 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_l2_addr_msg_distribute_set");
1652 ret = BCM_ERR_INTERNAL;
1653 break;
1654 }
1655 }
1656 }
1657 else
1658 {
1659 /* vsi service needs down stream info for in LIF VLAN info */
1660 p_vsi_svc = bal_sw_util_dpp_vsi_service_create(unit, p_ds_flow, &svc_tag_indx);
1661 if(p_vsi_svc == NULL)
1662 {
1663 BCM_LOG(ERROR, log_id_sw_util, "Error, vsi create failed\n");
1664 ret = BCM_ERR_INTERNAL;
1665 break;
1666 }
1667 vsi = p_vsi_svc->vswitch;
1668 }
1669 /* === create a PON LIF === */
1670
1671 /* if DS SLA is set, create a VOQ id, otherwise use local port id */
1672 /** @note QoS from the Downstream flow config is taken to configure SLA in the switch. Upstream is done in MAC.
1673 */
1674 if ((p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM) && (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, sla)))
1675 {
1676 p_service_cfg = bcmos_calloc(sizeof(bal_sw_dpp_qos_service_cfg));
1677 if (p_service_cfg == NULL)
1678 {
1679 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to alloc a bal_sw_dpp_qos_service_cfg_t\n");
1680 ret = BCM_ERR_INTERNAL;
1681 break;
1682 }
1683
1684 p_service_cfg->service_type = BAL_BCM_SVC_TYPE_IP;
1685 p_service_cfg->bal_flow_id = p_flow->key.flow_id;
1686 p_service_cfg->pon_port = p_flow->data.access_int_id;
1687 p_service_cfg->tunnel_id = tunnel_id;
1688 /* TBD - channelize port config */
1689 p_service_cfg->ds_qos.pon_chan = 0;
1690 p_service_cfg->ds_qos.min.rate = p_flow->data.sla.min_rate;
1691 /* burst - set it to twice the rate */
1692 max_burst = ( (2*p_service_cfg->ds_qos.min.rate) < BAL_MAX_BURST_RATE )? (2*p_service_cfg->ds_qos.min.rate): BAL_MAX_BURST_RATE;
1693 p_service_cfg->ds_qos.min.burst = max_burst;
1694 /* TBD priority */
1695 p_service_cfg->ds_qos.min.traffic_priority = 2;
1696
1697 p_service_cfg->ds_qos.max.rate = p_flow->data.sla.max_rate - p_flow->data.sla.min_rate;
1698 /* burst - set it to twice the rate */
1699 max_burst = ( (2*p_service_cfg->ds_qos.max.rate) < BAL_MAX_BURST_RATE )? (2*p_service_cfg->ds_qos.max.rate): BAL_MAX_BURST_RATE;
1700 p_service_cfg->ds_qos.max.burst = max_burst;
1701 /* TBD priority */
1702 p_service_cfg->ds_qos.max.traffic_priority = 2;
1703 ret = bal_sw_dpp_llid_qos_config(unit, p_service_cfg);
1704 /* Check for errors */
1705 if (ret != BCM_ERR_OK)
1706 {
1707 /* Failure */
1708 BCM_LOG(WARNING, log_id_sw_util,
1709 "Downstream QoS configuration failed for pon %u tid %u\n",
1710 p_flow->data.access_int_id, tunnel_id);
1711 break;
1712 }
1713 BCM_GPORT_UNICAST_QUEUE_GROUP_SET(pon, p_service_cfg->ds_qos.voq_flow_id);
1714 sys_pon = p_service_cfg->ds_qos.voq_gport;
1715 BCM_LOG(INFO, log_id_sw_util, " use voq_id 0x%x queue group 0x%x, voq_gport 0x%x to create PON LIFT\n", p_service_cfg->ds_qos.voq_flow_id, pon, sys_pon);
1716
1717 /* clear the VOQ stats here */
1718 bal_sw_dpp_qos_clear_voq_stats(unit, sys_pon);
1719 }
1720 else
1721 {
1722 sys_pon = pon;
1723 BCM_LOG(INFO, log_id_sw_util, " use pp port 0x%x to create PON LIFT\n", pon);
1724 }
1725
1726 /* Configure the switch pon LIF based on classifier in the flow.
1727 The pon LIF filter the ingress packets from PON, so use the classifier in the US direction.
1728 This means, if the original flow configuration is for Downstream, use the reverse flow that locally created */
1729
1730 bcm_vlan_port_t_init(&vp);
1731
1732 /* preserve any incoming packet vlan tags, if vlan actions are required, do it using egress translation */
1733 vp.flags = BCM_VLAN_PORT_OUTER_VLAN_PRESERVE | BCM_VLAN_PORT_INNER_VLAN_PRESERVE;
1734 /* It is required to set the FEC flag so that the egress redirection action from the DS classification can
1735 select the correct PON LIF to forward the packet */
1736 vp.flags |= BCM_VLAN_PORT_FORWARD_GROUP;
1737
1738
1739 switch(p_us_flow->data.classifier.pkt_tag_type)
1740 {
1741 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
1742 /* match both tunnel and outer tag on ingress PON */
1743 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_us_flow->data.classifier, classifier, o_pbits))
1744 {
1745 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_PCP_VLAN;
1746 vp.match_pcp = p_us_flow->data.classifier.o_pbits;
1747 }
1748 else
1749 {
1750 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_VLAN;
1751 }
1752 break;
1753 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
1754 /* Otherwise match both tunnel and both outer and inner tags on ingress PON */
1755 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_us_flow->data.classifier, classifier, o_pbits))
1756 {
1757 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_PCP_VLAN_STACKED;
1758 vp.match_pcp = p_us_flow->data.classifier.o_pbits;
1759 }
1760 else
1761 {
1762 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL_VLAN_STACKED;
1763 }
1764 break;
1765 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
1766 /* Otherwise match tunnel tag on ingress PON */
1767 {
1768 vp.criteria = BCM_VLAN_PORT_MATCH_PORT_TUNNEL;
1769 }
1770 break;
1771 default:
1772 /* should not reach here */
1773 BCM_LOG(ERROR, log_id_sw_util, "Error, Unsupported packet type %d for pon LIF\n",p_us_flow->data.classifier.pkt_tag_type );
1774 return BCM_ERR_INTERNAL;
1775 }
1776
1777
1778 vp.port = pon;
1779 vp.match_tunnel_value = tunnel_id;
1780 vp.egress_tunnel_value = tunnel_id;
1781 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_us_flow->data.classifier, classifier, o_vid))
1782 {
1783 vp.match_vlan = p_us_flow->data.classifier.o_vid;
1784 }
1785 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_us_flow->data.classifier, classifier, i_vid))
1786 {
1787 vp.match_inner_vlan = p_us_flow->data.classifier.i_vid;
1788 }
1789 vp.vsi = 0; /* will be populated when the gport is added to service, using vswitch_port_add */
1790
1791 /* Create the vlan port (i.e., PON LIF) */
1792 rv = bcm_vlan_port_create(unit, &vp);
1793 if (rv != BCM_E_NONE)
1794 {
1795 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_vlan_port_create pon %d failed %d\n", pon, rv);
1796 ret = BCM_ERR_INTERNAL;
1797 break;
1798 }
1799
1800 pon_gport = vp.vlan_port_id;
1801 /* set pon gport to first element of the array */
1802 flow_elm.pon_port[0] = pon_gport;
1803
1804 /* set PON port DISCARD mode to reflect the flow direction. When two BAL flows with same id and different directions
1805 are configured, the DISCARD mode will be set back to NONE */
1806 if (flow_elm.type == BAL_SW_FLOW_TYPE_DOWNSTREAM)
1807 {
1808 BCM_LOG(INFO, log_id_sw_util, "Info, bcm_port_discard_set pon 0x%x to DISCARD_INGRESS\n", pon_gport);
1809 rv = bcm_port_discard_set(unit, pon_gport, BCM_PORT_DISCARD_INGRESS);
1810 }
1811 else if (flow_elm.type == BAL_SW_FLOW_TYPE_UPSTREAM)
1812 {
1813 /* allow bi-direction for N:1 service */
1814 if( BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_us_flow, flow, group_id) &&
1815 BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_us_flow, flow, resolve_mac) &&
1816 BCMOS_TRUE == p_us_flow->data.resolve_mac)
1817 {
1818 rv = BCM_E_NONE;
1819 }
1820 else
1821 {
1822 BCM_LOG(INFO, log_id_sw_util, "Info, bcm_port_discard_set pon 0x%x to DISCARD_EGRESS\n", pon_gport);
1823 rv = bcm_port_discard_set(unit, pon_gport, BCM_PORT_DISCARD_EGRESS);
1824 }
1825 }
1826 else
1827 {
1828 rv = BCM_E_NONE;
1829 }
1830
1831 if (rv != BCM_E_NONE)
1832 {
1833 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_discard_set failed %d\n", rv);
1834 /* ARAD does not support the DISCARD function as of 6.5.4 */
1835#ifdef QAX_SWITCH
1836 ret = BCM_ERR_INTERNAL;
1837 break;
1838#endif
1839 }
1840
1841 // add pon gport to vswitch
1842 rv = bcm_vswitch_port_add(unit, vsi, pon_gport);
1843 if (rv != BCM_E_NONE)
1844 {
1845 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_vswitch_port_add for pon 0x%x failed %d\n", pon, rv);
1846 ret = BCM_ERR_INTERNAL;
1847 break;
1848 }
1849 else
1850 {
1851 BCM_LOG(INFO, log_id_sw_util, "Info, bcm_vswitch_port_add for pon 0x%x, gport 0x%x\n", pon, pon_gport);
1852 }
1853
1854 if(BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, group_id) &&
1855 BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, resolve_mac) &&
1856 BCMOS_TRUE == p_flow->data.resolve_mac)
1857 {
1858 /* for flows that need to resolve mac, don't forward unknown traffics */
1859 BCM_LOG(DEBUG, log_id_sw_util, "pon %d:0x%x bypass downstream MC group join\n", pon, pon_gport);
1860 }
1861 else
1862 {
1863 // obtain encapsulation ID for legacy reason, used in ADD API */
1864 rv = bcm_multicast_vlan_encap_get(unit, p_vsi_svc->ds_flood_grp_id, sys_pon, pon_gport, &pon_encap_id);
1865 if (rv != BCM_E_NONE)
1866 {
1867 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_vlan_encap_get for pon failed %d\n", rv);
1868 ret = BCM_ERR_INTERNAL;
1869 break;
1870 }
1871 /* join the downstream multicast group as a member of replication list */
1872 rv = bcm_multicast_ingress_add(unit, p_vsi_svc->ds_flood_grp_id, sys_pon, pon_encap_id);
1873 if (rv != BCM_E_NONE)
1874 {
1875 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_multicast_ingress_add for pon failed %d\n", rv);
1876 ret = BCM_ERR_INTERNAL;
1877 break;
1878 }
1879 /* now set the type of packets that goes to the upstream flooding group (offset 0) */
1880 rv = bcm_port_control_set(unit, pon_gport, bcmPortControlFloodUnknownUcastGroup, BAL_DPP_US_FLOOD_OFFSET);
1881 if (rv != BCM_E_NONE)
1882 {
1883 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set ucast for pon failed %d\n", rv);
1884 }
1885 }
1886 rv = bcm_port_control_set(unit, pon_gport, bcmPortControlFloodUnknownMcastGroup, BAL_DPP_US_FLOOD_OFFSET);
1887 if (rv != BCM_E_NONE)
1888 {
1889 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set mcast for pon failed %d\n", rv);
1890 break;
1891 }
1892 rv = bcm_port_control_set(unit, pon_gport, bcmPortControlFloodBroadcastGroup, BAL_DPP_US_FLOOD_OFFSET);
1893 if (rv != BCM_E_NONE)
1894 {
1895 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_control_set bcast for pon failed %d\n", rv);
1896 break;
1897 }
1898 /* perform vlan translation on pon port, pon egress info is in the Downstream configuration */
1899 if (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_ds_flow, flow, action))
1900 {
1901 ret = bal_sw_util_dpp_invlanx(unit, p_us_flow, pon_gport);
1902 if (ret != BCM_ERR_OK)
1903 {
1904 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perform ingress vlan translation on pon %d\n", pon);
1905 break;
1906 }
1907 ret = bal_sw_util_dpp_evlanx(unit, p_ds_flow, pon_gport);
1908 if (ret != BCM_ERR_OK)
1909 {
1910 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perform egress vlan translation on pon %d\n", pon);
1911 break;
1912 }
1913 }
1914 /* === PON LIF created === */
1915
1916 ii = 0; /* Start with the first NNI logical interface */
1917 /* loop through all nni port, add them to vswitch, -1 indicate end of table */
1918 /* Configure the switch nni LIF based on classifier in the flow.
1919 The nni LIF filter the ingress packets from Network, so use the classifier in the DS direction.
1920 This means, if the original flow configuration is for Upstream, use the reverse flow that locally created */
1921 while(-1 != (nni = bal_bcm_net_inf_pbm_get(ii)))
1922 {
1923 /* skip nni port that is not in the same device or not valid */
1924 if ( bal_bcm_net_inf_dev_get(ii) != unit ||
1925 BCMOS_FALSE == bcm_topo_nni_is_valid(ii))
1926 {
1927 ii++;
1928 continue;
1929 }
1930
1931 /* if nni port is specified in the flow, skip the other nni ports */
1932 if ( BCMBAL_CFG_PROP_IS_SET(p_ds_flow, flow, network_int_id) &&
1933 ii != p_ds_flow->data.network_int_id
1934 )
1935 {
1936 ii++;
1937 continue;
1938 }
1939
1940 /* create gport based on nni physical port number */
1941
1942 ret = bal_sw_util_dpp_vsi_service_port_add(unit, p_vsi_svc, svc_tag_indx, nni, &nni_gport);
1943 if (ret != BCM_ERR_OK)
1944 {
1945 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add nni %d to vsi\n", nni);
1946 break;
1947 }
1948
1949 flow_elm.net_port[flow_elm.num_net] = nni_gport;
1950 flow_elm.num_net++;
1951
1952 /* perform vlan translation on nni port, nni egress info is in the Upstream configuration */
1953 if (BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_us_flow, flow, action))
1954 {
1955 rv = bcm_vlan_control_port_set(unit, nni_gport, bcmVlanPortTranslateKeyFirst, bcmVlanTranslateKeyPortOuter);
1956 if (rv != BCM_E_NONE)
1957 {
1958 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perform vlan control port set on nni %d\n", nni);
1959 break;
1960 }
1961 ret = bal_sw_util_dpp_invlanx(unit, p_ds_flow, nni_gport);
1962 if (ret != BCM_ERR_OK)
1963 {
1964 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perform ingress vlan translation on nni %d\n", nni);
1965 break;
1966 }
1967
1968 ret = bal_sw_util_dpp_evlanx(unit, p_us_flow, nni_gport);
1969 if (ret != BCM_ERR_OK)
1970 {
1971 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perfrom egress vlan translation on nni %d\n", nni);
1972 break;
1973 }
1974 }
1975 /* if classifier is more than just port + VLAN tags, add ACL rule to re-direct packet to egress port.
1976 This bypass the ingress LIF as LIF check VID only.
1977 Upstream classification is expected to be done in ONU (onu add GEM based on classifiers for upstream) */
1978 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM &&
1979 bal_sw_util_flow_ds_acl_cls_chk(p_ds_flow) == BCMOS_TRUE )
1980 {
1981 /* add re-direct rule */
1982 if( BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_ds_flow, flow, network_int_id))
1983 {
1984 ret = bal_sw_util_dpp_acl_add(unit, p_ds_flow, &flow_elm, nni_gport, pon_gport);
1985 }
1986 else /* Rule need to match the network port, otherwise, it will apply to all ports - nni and pon */
1987 {
1988 BCMBAL_CFG_PROP_SET(p_ds_flow, flow, network_int_id, ii);
1989 ret = bal_sw_util_dpp_acl_add(unit, p_ds_flow, &flow_elm, nni_gport, pon_gport);
1990 BCMBAL_CFG_PROP_CLEAR(p_ds_flow, flow, network_int_id);
1991 }
1992 if (ret != BCM_ERR_OK)
1993 {
1994 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add forwarding acl on nni %d, ret = %d\n", ret, ii);
1995 break;
1996 }
1997 /* add a dft drop rule (priority 0) on the LIF to drop packets that match VID but no match for other fields */
1998 ret = bal_sw_util_dpp_dft_acl_add(unit, p_ds_flow, &flow_elm, nni_gport);
1999 if (ret != BCM_ERR_OK)
2000 {
2001 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add default acl on nni=0x%x, ret = %d\n", nni_gport, ret);
2002 break;
2003 }
2004 }
2005 /* If the user needs to perfrom upstream classification (in addition to VID),
2006 Add an ACL rule to re-direct packets. The ACL also allow upstream flows to be prioritized based on priority field */
2007 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM &&
2008 bal_sw_util_flow_us_acl_cls_chk(p_us_flow) == BCMOS_TRUE &&
2009 /* there are issues using traditional API for PON application when egress vlan translation and ingress ACL are both active.
2010 Enable the ACL only when there is no vlan action - TBD */
2011 BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action))
2012 {
2013 /* ACL requires an action, currently support trap or re-direct the flow.
2014 TRAP has been handle in other path, here we require user to specify which port to re-direct.
2015 Other options will be adding multiple ACL to cover all possible egress ports - TBD */
2016 if( BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_us_flow, flow, network_int_id))
2017 {
2018 BCM_LOG(ERROR, log_id_sw_util, "Error, Upstream classifier in addition to VID without NNI port set is not suppotred\n");
2019 break;
2020 }
2021 else
2022 {
2023 ret = bal_sw_util_dpp_acl_add(unit, p_us_flow, &flow_elm, pon_gport, nni_gport);
2024 }
2025 if (ret != BCM_ERR_OK)
2026 {
2027 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add forwarding acl on pon %d, ret = %d\n", ret, pon);
2028 break;
2029 }
2030 /* add a default drop rule (priority 0) on the LIF to drop packets that match VID but no match for other fields */
2031 ret = bal_sw_util_dpp_dft_acl_add(unit, p_us_flow, &flow_elm, pon_gport);
2032 if (ret != BCM_ERR_OK)
2033 {
2034 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to add default acl on pon=0x%x, ret = %d\n", pon_gport, ret);
2035 break;
2036 }
2037 }
2038
2039 ii++; /* Next NNI */
2040 }
2041 /* skip the rest if anything goes wrong */
2042 if( ret != BCM_ERR_OK)
2043 {
2044 break;
2045 }
2046 /* Configure PCP/Cos to Traffic Class mapping. This has to be done after the NNI LIFs are created */
2047 if (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM && BCMOS_TRUE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, sla))
2048 {
2049 p_service_cfg->num_nni_gport = flow_elm.num_net;
2050 for( ii = 0; ii < p_service_cfg->num_nni_gport; ii++)
2051 {
2052 p_service_cfg->nni_gport[ii] = flow_elm.net_port[ii];
2053 }
2054 ret = bal_sw_dpp_llid_set_qos_port_map(unit, p_service_cfg);
2055 if (ret != BCM_ERR_OK)
2056 {
2057 BCM_LOG(ERROR, log_id_sw_util, "Error, fail to perfrom nni qos port map, ret = %d\n", ret);
2058 break;
2059 }
2060 }
2061
2062 } while(0);
2063
2064 if( ret == BCM_ERR_OK)
2065 {
2066 /* add the flow info to the link list */
2067 flow_elm.p_vsi_svc = p_vsi_svc;
2068 flow_elm.vsi_svc_indx = svc_tag_indx;
2069 flow_elm.num_pon = 1;
2070 flow_elm.p_service_cfg = p_service_cfg;
2071
2072 /* nni ports are done in the nni loop */
2073 flow_elm.valid = 1;
2074 bal_sw_util_flow_list_insert(flow_elm);
2075
2076 BCM_LOG(INFO, log_id_sw_util, "Add flow_elm %d type %d, vswitch 0x%x, Success\n", flow_elm.id, flow_elm.type, p_vsi_svc->vswitch);
2077 }
2078 return ret;
2079}
2080
2081
2082/**
2083 * @brief The internal flow remove function program DPP to release resource that
2084 * were allocated during the ADD operation
2085 *
2086 * @param p_flow_elm a pointer to the internal flow list
2087 *
2088 * @return error code
2089 */
2090bcmos_errno bal_sw_util_dpp_flow_remove_int(bal_sw_flow *p_flow_elm)
2091{
2092 bcmos_errno ret = BCM_ERR_OK;
2093 int rv, i, flow_id;
2094 bal_sw_vsi_service *p_vsi_svc;
2095 bal_sw_group_list *p_group_list;
2096
2097 if(p_flow_elm == NULL)
2098 {
2099 BCM_LOG(ERROR, log_id_sw_util, " invalid pointer to the internal flow list\n");
2100 return BCM_ERR_INTERNAL;
2101 }
2102 p_vsi_svc = (bal_sw_vsi_service *) p_flow_elm->p_vsi_svc;
2103 /* if anything go wrong, log a warning and continue release resources */
2104 for(i = 0; i <p_flow_elm->num_pon; i++)
2105 {
2106 rv = bcm_vswitch_port_delete(p_flow_elm->device, p_vsi_svc->vswitch, p_flow_elm->pon_port[i]);
2107 if(rv)
2108 {
2109 BCM_LOG(WARNING, log_id_sw_util, " vswitch pon port 0x%x delete failed %d\n", p_flow_elm->pon_port[i], rv);
2110 }
2111 rv = bcm_vlan_port_destroy(p_flow_elm->device, p_flow_elm->pon_port[i]);
2112 if(rv)
2113 {
2114 BCM_LOG(WARNING, log_id_sw_util, " vswitch pon port 0x%x destroy failed %d\n", p_flow_elm->pon_port[i], rv);
2115 }
2116 p_flow_elm->pon_port[i] = 0;
2117 }
2118 p_flow_elm->num_pon = 0;
2119
2120 for(i = 0; i <p_flow_elm->num_net; i++)
2121 {
2122 ret = bal_sw_util_dpp_vsi_service_port_rem(p_flow_elm->device, p_flow_elm->p_vsi_svc, p_flow_elm->vsi_svc_indx, p_flow_elm->net_port[i]);
2123 if(ret != BCM_ERR_OK)
2124 {
2125 BCM_LOG(WARNING, log_id_sw_util, " vsi service port 0x%x remove failed %d\n", p_flow_elm->net_port[i], ret);
2126 }
2127
2128 p_flow_elm->net_port[i] = 0;
2129 }
2130 p_flow_elm->num_net = 0;
2131
2132 /* release vswitch */
2133 if (p_vsi_svc)
2134 {
2135 /* remove the vsi if no more service, destroy function will do the counting */
2136 ret = bal_sw_util_dpp_vsi_service_destroy(p_flow_elm->device, p_vsi_svc);
2137 if(ret != BCM_ERR_OK)
2138 {
2139 BCM_LOG(WARNING, log_id_sw_util, " vsi service destroy failed %d\n", ret);
2140 }
2141 }
2142 /* decrement the group reference counter in the group list */
2143 if (p_flow_elm->group_id)
2144 {
2145 p_group_list = bal_sw_util_dpp_group_list_get_by_id(p_flow_elm->group_id);
2146 if ( p_group_list == NULL)
2147 {
2148 BCM_LOG(WARNING, log_id_sw_util,
2149 " WARNING: MC flow remove can't find the mc group %d in the list\n", p_flow_elm->group_id);
2150 }
2151 else
2152 {
2153 if(p_group_list->use_count)
2154 {
2155 p_group_list->use_count--;
2156 }
2157 else
2158 {
2159 BCM_LOG(WARNING, log_id_sw_util,
2160 " WARNING: MC flow remove find the mc group %d in the list has no use_count\n", p_flow_elm->group_id);
2161 }
2162 }
2163 }
2164
2165 /* relese trap */
2166 if (p_flow_elm->trap_code)
2167 {
2168 rv = bcm_rx_trap_type_destroy(p_flow_elm->device, p_flow_elm->trap_code);
2169 if(rv)
2170 {
2171 BCM_LOG(WARNING, log_id_sw_util, " rx trap %d destroy failed %d\n", p_flow_elm->trap_code, rv);
2172 }
2173 p_flow_elm->trap_code = 0;
2174 p_flow_elm->trap_port = 0;
2175 }
2176
2177 /* release acl, if any */
2178 for(i = 0; i <p_flow_elm->num_eid; i++)
2179 {
2180 if (p_flow_elm->field_entry_id[i])
2181 {
2182 rv = bcm_field_entry_remove(p_flow_elm->device, p_flow_elm->field_entry_id[i]);
2183 if(rv)
2184 {
2185 BCM_LOG(WARNING, log_id_sw_util, " field entry %d remove failed %d\n", p_flow_elm->field_entry_id[i], rv);
2186 }
2187 rv = bcm_field_entry_destroy(p_flow_elm->device, p_flow_elm->field_entry_id[i]);
2188 if(rv)
2189 {
2190 BCM_LOG(WARNING, log_id_sw_util, " field entry %d destroy failed %d\n", p_flow_elm->field_entry_id[i], rv);
2191 }
2192 p_flow_elm->field_entry_id[i] = 0;
2193 }
2194 }
2195 p_flow_elm->num_eid = 0;
2196
2197 /* release llid qos, if any */
2198 if (p_flow_elm->p_service_cfg)
2199 {
2200 /* any error during cleanup will be reported, but continue anyway */
2201 bal_sw_dpp_llid_qos_cleanup(p_flow_elm->device, (bal_sw_dpp_qos_service_cfg *)p_flow_elm->p_service_cfg);
2202 bcmos_free(p_flow_elm->p_service_cfg);
2203 p_flow_elm->p_service_cfg = NULL;
2204 }
2205
2206 /* remove from the internal link list */
2207 flow_id = p_flow_elm->id;
2208 ret = bal_sw_util_flow_list_remove(p_flow_elm);
2209 if(ret == BCM_ERR_OK)
2210 {
2211 BCM_LOG(INFO, log_id_sw_util, " flow %d is removed\n", flow_id);
2212 ret = BCM_ERR_OK;
2213 }
2214 else
2215 {
2216 BCM_LOG(WARNING, log_id_sw_util, " fail to remove flow %d w ret = %d\n", flow_id, ret);
2217 ret = BCM_ERR_INTERNAL;
2218 }
2219 return ret;
2220}
2221
2222/**
2223 * @brief The flow remove function program DPP to release resource that
2224 * were allocated during the ADD operation
2225 *
2226 * @param iwf_mode The InterWorking Function mode - DIRECT or PER-FLOW
2227 * @param p_flow A pointer to the requested add flow info
2228 * @return error code
2229 */
2230bcmos_errno bal_sw_util_dpp_flow_remove(bcmbal_iwf_mode iwf_mode, bcmbal_flow_cfg *p_flow)
2231{
2232 bcmos_errno ret = BCM_ERR_OK;
2233 bal_sw_flow *p_flow_elm;
2234 int ii, rv;
2235 bcm_port_discard_t discard_type = BCM_PORT_DISCARD_NONE;
2236
2237 if(p_flow == NULL)
2238 {
2239 BCM_LOG(ERROR, log_id_sw_util, " invalid pointer to the bal flow\n");
2240 return BCM_ERR_INTERNAL;
2241 }
2242
2243 /* make sure the flow id is in the link list, if not return success anyway (probably clearing a DOWN flow) */
2244 p_flow_elm = bal_sw_util_flow_list_get_by_id (p_flow->key.flow_id);
2245 if(p_flow_elm == NULL)
2246 {
2247 BCM_LOG(WARNING, log_id_sw_util, " flow %d not exist the link list\n", p_flow->key.flow_id);
2248 return BCM_ERR_OK;
2249 }
2250
2251 /* if flow_elm has the requested direction, set switch to discard packets from the requested direction. */
2252 if( (p_flow_elm->type & BAL_SW_FLOW_TYPE_DOWNSTREAM) &&
2253 (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM)
2254 )
2255 {
2256 discard_type = BCM_PORT_DISCARD_EGRESS;
2257 }
2258 else if ((p_flow_elm->type & BAL_SW_FLOW_TYPE_UPSTREAM) &&
2259 (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)
2260 )
2261 {
2262 discard_type = BCM_PORT_DISCARD_INGRESS;
2263 }
2264 else if (p_flow_elm->type & BAL_SW_FLOW_TYPE_MULTICAST)
2265 {
2266 /* clear rhe type so that it can remove the flow below */
2267 p_flow_elm->type &= ~BAL_SW_FLOW_TYPE_MULTICAST;
2268 }
2269
2270 if (discard_type != BCM_PORT_DISCARD_NONE)
2271 {
2272 for(ii=0; ii<p_flow_elm->num_pon; ii++)
2273 {
2274 if(p_flow_elm->pon_port[ii] == 0)
2275 {
2276 /* if PON LIF is deleted, then continue to the next pon */
2277 continue;
2278 }
2279 rv = bcm_port_discard_set(p_flow_elm->device, p_flow_elm->pon_port[ii], discard_type);
2280 if (rv != BCM_E_NONE)
2281 {
2282 /* mark an error, but continue */
2283 BCM_LOG(ERROR, log_id_sw_util, "Error, bcm_port_discard_set failed %d on pon 0x%x\n", rv, p_flow_elm->pon_port[ii]);
2284 ret = BCM_ERR_INTERNAL;
2285 }
2286 }
2287 if (BCM_ERR_OK == ret)
2288 {
2289 if( p_flow->key.flow_type == BCMBAL_FLOW_TYPE_DOWNSTREAM)
2290 {
2291 p_flow_elm->type &= ~BAL_SW_FLOW_TYPE_DOWNSTREAM;
2292 }
2293 else if (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM)
2294 {
2295 p_flow_elm->type &= ~BAL_SW_FLOW_TYPE_UPSTREAM;
2296 }
2297 BCM_LOG(INFO, log_id_sw_util, " Success remove flow %d with type %d\n", p_flow->key.flow_id, p_flow->key.flow_type);
2298 }
2299 }
2300 /* remove the flow from the list if everything is cleanup */
2301 if(BAL_SW_FLOW_TYPE_NONE == p_flow_elm->type)
2302 {
2303 ret = bal_sw_util_dpp_flow_remove_int(p_flow_elm);
2304 }
2305
2306 return ret;
2307}
2308
2309
2310
2311/*******************************
2312 * Helper routines below
2313 *******************************/
2314/**
2315 * @brief Helper routine to reverse a flow i.e. an upstream flow is made a downstream flow
2316 * and vice versa
2317 *
2318 * @param p_flow A pointer to the original flow
2319 * @param p_flow_rev A pointer to the reversed flow
2320 * @return error code
2321 *
2322 * @note for now it assumes an untagged or single tagged vlan flow with single vlan tag classificiation
2323 */
2324static bcmos_errno bal_sw_util_reverse_flow_create(bcmbal_flow_cfg *p_flow, bcmbal_flow_cfg *p_flow_rev)
2325{
2326 bcmos_errno ret = BCM_ERR_OK;
2327
2328 if ((p_flow == NULL) || (p_flow_rev == NULL))
2329 {
2330 return BCM_ERR_INTERNAL;
2331 }
2332
2333 /* reverse parameters in flow */
2334 memcpy(p_flow_rev, p_flow, sizeof(bcmbal_flow_cfg));
2335
2336 p_flow_rev->key.flow_type = (p_flow->key.flow_type == BCMBAL_FLOW_TYPE_UPSTREAM ?
2337 BCMBAL_FLOW_TYPE_DOWNSTREAM : BCMBAL_FLOW_TYPE_UPSTREAM);
2338
2339 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_mac))
2340 {
2341 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, src_mac, p_flow->data.classifier.dst_mac);
2342 }
2343 else /* clear the src_mac presence mask in the reverse flow */
2344 {
2345 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, src_mac);
2346 }
2347
2348 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_mac))
2349 {
2350 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, dst_mac, p_flow->data.classifier.src_mac);
2351 }
2352 else /* clear the dst_mac presence mask in the reverse flow */
2353 {
2354 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, dst_mac);
2355 }
2356
2357 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_port))
2358 {
2359 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, src_port, p_flow->data.classifier.dst_port);
2360 }
2361 else /* clear the src_port presence mask in the reverse flow */
2362 {
2363 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, src_port);
2364 }
2365
2366 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_port))
2367 {
2368 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, dst_port, p_flow->data.classifier.src_port);
2369 }
2370 else /* clear the dst_port presence mask in the reverse flow */
2371 {
2372 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, dst_port);
2373 }
2374
2375 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, dst_ip))
2376 {
2377 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, src_ip, p_flow->data.classifier.dst_ip);
2378 }
2379 else /* clear the src_ip presence mask in the reverse flow */
2380 {
2381 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, src_ip);
2382 }
2383
2384 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, src_ip))
2385 {
2386 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, dst_ip, p_flow->data.classifier.src_ip);
2387 }
2388 else /* clear the dst_ip presence mask in the reverse flow */
2389 {
2390 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, dst_ip);
2391 }
2392
2393
2394 if (BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG))
2395 {
2396 BCMBAL_ACTION_CMD_ID_CLEAR(&(p_flow_rev->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG);
2397 BCMBAL_ACTION_CMD_ID_SET(&(p_flow_rev->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG);
2398
2399 /* remove o_vid from action */
2400 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.action, action, o_vid);
2401
2402 switch(p_flow->data.classifier.pkt_tag_type)
2403 {
2404 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
2405 /* ADD on untagged packet result to single tagged on revert direction */
2406 p_flow_rev->data.classifier.pkt_tag_type = BCMBAL_PKT_TAG_TYPE_SINGLE_TAG;
2407 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, o_vid, p_flow->data.action.o_vid);
2408 break;
2409 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
2410 /* ADD on single tagged packet result to double tagged on revert direction */
2411 p_flow_rev->data.classifier.pkt_tag_type = BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG;
2412 p_flow_rev->data.classifier.o_vid = p_flow->data.action.o_vid;
2413 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, i_vid, p_flow->data.classifier.o_vid);
2414 break;
2415 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
2416 default:
2417 /* should not reach here */
2418 break;
2419 }
2420 }
2421 else if (BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG))
2422 {
2423 BCMBAL_ACTION_CMD_ID_CLEAR(&(p_flow_rev->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG);
2424 BCMBAL_ACTION_CMD_ID_SET(&(p_flow_rev->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG);
2425
2426 /* add o_vid to action */
2427 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.action, action, o_vid, p_flow->data.classifier.o_vid);
2428 switch(p_flow->data.classifier.pkt_tag_type)
2429 {
2430 case BCMBAL_PKT_TAG_TYPE_DOUBLE_TAG:
2431 /* REMOVE on double tagged packet result to single tagged on revert direction */
2432 p_flow_rev->data.classifier.pkt_tag_type = BCMBAL_PKT_TAG_TYPE_SINGLE_TAG;
2433 p_flow_rev->data.classifier.o_vid = p_flow->data.classifier.i_vid;
2434 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, i_vid);
2435 break;
2436 case BCMBAL_PKT_TAG_TYPE_SINGLE_TAG:
2437 /* REMOVE on single tagged packet result to untagged on revert direction */
2438 p_flow_rev->data.classifier.pkt_tag_type = BCMBAL_PKT_TAG_TYPE_UNTAGGED;
2439 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, o_vid);
2440 break;
2441 case BCMBAL_PKT_TAG_TYPE_UNTAGGED:
2442 default:
2443 /* should not reach here */
2444 break;
2445 }
2446 /* if the remove classifier has tpid attribute, set it when ADD in reverse direction */
2447 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_tpid))
2448 {
2449 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.action, action, o_tpid, p_flow->data.classifier.o_tpid);
2450 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.classifier, classifier, o_tpid);
2451 }
2452 }
2453 else if (BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_XLATE_OUTER_TAG))
2454 {
2455 /* swap output vid and classifier parameters */
2456 p_flow_rev->data.action.o_vid = p_flow->data.classifier.o_vid;
2457 p_flow_rev->data.classifier.o_vid = p_flow->data.action.o_vid;
2458 }
2459
2460 if (BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_REMARK_PBITS))
2461 {
2462 /* swap output pbits and classifier parameters */
2463 if(BCMOS_TRUE == BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_pbits))
2464 {
2465 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.action, action, o_pbits, p_flow->data.classifier.o_pbits);
2466 }
2467 else
2468 {
2469 /* if the pbits remark is for packets with any o_pibts, then there is no clear REVERSE operation.
2470 Set the reverse to NO pbits action. i.e pbits is a passthrough
2471 */
2472 BCMBAL_ATTRIBUTE_PROP_CLEAR(&p_flow_rev->data.action, action, o_pbits);
2473 BCMBAL_ACTION_CMD_ID_CLEAR(&(p_flow_rev->data.action), BCMBAL_ACTION_CMD_ID_REMARK_PBITS);
2474 }
2475
2476 BCMBAL_ATTRIBUTE_PROP_SET(&p_flow_rev->data.classifier, classifier, o_pbits, p_flow->data.action.o_pbits);
2477 }
2478 //else tbd
2479
2480
2481 return ret;
2482}
2483
2484/**
2485 * @brief Helper routine to compare two flows for symmetry
2486 *
2487 * @param p_flow A pointer to the original flow
2488 * @param p_ref_flow A pointer to the reference flow
2489 * @return TRUE or FALSE
2490 */
2491bcmos_bool bal_sw_util_is_symmetry_flows(bcmbal_flow_cfg *p_flow, bcmbal_flow_cfg *p_ref_flow)
2492{
2493 bcmos_bool ret = BCMOS_TRUE;
2494
2495 /* compare the access interface */
2496 if( BCMBAL_CFG_PROP_IS_SET(p_flow, flow, access_int_id) !=
2497 BCMBAL_CFG_PROP_IS_SET(p_ref_flow, flow, access_int_id) )
2498 {
2499 BCM_LOG(INFO, log_id_sw_util, " access interface SET not the same for flow %d\n", p_flow->key.flow_id);
2500 ret = BCMOS_FALSE;
2501 }
2502 else
2503 {
2504 if( (BCMBAL_CFG_PROP_IS_SET(p_flow, flow, access_int_id) || BCMBAL_CFG_PROP_IS_SET(p_ref_flow, flow, access_int_id)) &&
2505 (p_flow->data.access_int_id != p_ref_flow->data.access_int_id) )
2506 {
2507 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream access interface %d != %d \n",
2508 p_flow->key.flow_id, p_flow->data.access_int_id, p_ref_flow->data.access_int_id );
2509 ret = BCMOS_FALSE;
2510 }
2511 }
2512 /* compare the network interface */
2513 if( BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id) !=
2514 BCMBAL_CFG_PROP_IS_SET(p_ref_flow, flow, network_int_id) )
2515 {
2516 BCM_LOG(INFO, log_id_sw_util, " network interface SET not the same for flow %d\n", p_flow->key.flow_id);
2517 ret = BCMOS_FALSE;
2518 }
2519 else
2520 {
2521 if( (BCMBAL_CFG_PROP_IS_SET(p_flow, flow, network_int_id) ||BCMBAL_CFG_PROP_IS_SET(p_ref_flow, flow, network_int_id)) &&
2522 (p_flow->data.network_int_id != p_ref_flow->data.network_int_id) )
2523 {
2524 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream access interface %d != %d \n",
2525 p_flow->key.flow_id, p_flow->data.network_int_id, p_ref_flow->data.network_int_id );
2526 ret = BCMOS_FALSE;
2527 }
2528 }
2529
2530 /* if there is no action for the flow, packet type and VIDs should be the same */
2531 /* compare the IPv4 addresses */
2532 if(BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_flow, flow, action) &&
2533 BCMOS_FALSE == BCMBAL_CFG_PROP_IS_SET(p_ref_flow, flow, action))
2534 {
2535 /* check packet type */
2536 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type) !=
2537 BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_ref_flow->data.classifier, classifier, pkt_tag_type) )
2538 {
2539 BCM_LOG(INFO, log_id_sw_util, " packet type SET not the same for flow %d\n", p_flow->key.flow_id);
2540 ret = BCMOS_FALSE;
2541 }
2542 else
2543 {
2544 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, pkt_tag_type) &&
2545 (p_flow->data.classifier.pkt_tag_type != p_ref_flow->data.classifier.pkt_tag_type) )
2546 {
2547 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream packet type %d != %d \n",
2548 p_flow->key.flow_id, p_flow->data.classifier.pkt_tag_type, p_ref_flow->data.classifier.pkt_tag_type );
2549 ret = BCMOS_FALSE;
2550 }
2551 }
2552
2553 /* check the outer VID */
2554 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid) !=
2555 BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_ref_flow->data.classifier, classifier, o_vid) )
2556 {
2557 BCM_LOG(INFO, log_id_sw_util, " outer vid SET not the same for flow %d\n", p_flow->key.flow_id);
2558 ret = BCMOS_FALSE;
2559 }
2560 else
2561 {
2562 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, o_vid) &&
2563 (p_flow->data.classifier.o_vid != p_ref_flow->data.classifier.o_vid) )
2564 {
2565 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream outer vid %d != %d \n",
2566 p_flow->key.flow_id, p_flow->data.classifier.o_vid, p_ref_flow->data.classifier.o_vid );
2567 ret = BCMOS_FALSE;
2568 }
2569 }
2570 /* check the inner VID */
2571 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid) !=
2572 BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_ref_flow->data.classifier, classifier, i_vid) )
2573 {
2574 BCM_LOG(INFO, log_id_sw_util, " inner vid SET not the same for flow %d\n", p_flow->key.flow_id);
2575 ret = BCMOS_FALSE;
2576 }
2577 else
2578 {
2579 if( BCMBAL_ATTRIBUTE_PROP_IS_SET(&p_flow->data.classifier, classifier, i_vid) &&
2580 (p_flow->data.classifier.i_vid != p_ref_flow->data.classifier.i_vid) )
2581 {
2582 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream inner vid %d != %d \n",
2583 p_flow->key.flow_id, p_flow->data.classifier.i_vid, p_ref_flow->data.classifier.i_vid );
2584 ret = BCMOS_FALSE;
2585 }
2586 }
2587
2588 }
2589 else /* if there is an action - action for VID must be symmetrical */
2590 {
2591 if(BCMOS_TRUE == BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG) &&
2592 BCMOS_FALSE == BCMBAL_ACTION_CMD_ID_IS_SET(&(p_ref_flow->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG) )
2593 {
2594 BCM_LOG(INFO, log_id_sw_util, " flow %d downstream/upstream outer vlan action not symmetrical \n", p_flow->key.flow_id );
2595 ret = BCMOS_FALSE;
2596 }
2597 if(BCMOS_TRUE == BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_REMOVE_OUTER_TAG) &&
2598 BCMOS_FALSE == BCMBAL_ACTION_CMD_ID_IS_SET(&(p_ref_flow->data.action), BCMBAL_ACTION_CMD_ID_ADD_OUTER_TAG))
2599 {
2600 BCM_LOG(INFO, log_id_sw_util, " flow %d upstream/downstream outer vlan action not symmetrical \n", p_flow->key.flow_id );
2601 ret = BCMOS_FALSE;
2602 }
2603 if(BCMBAL_ACTION_CMD_ID_IS_SET(&(p_flow->data.action), BCMBAL_ACTION_CMD_ID_XLATE_OUTER_TAG) !=
2604 BCMBAL_ACTION_CMD_ID_IS_SET(&(p_ref_flow->data.action), BCMBAL_ACTION_CMD_ID_XLATE_OUTER_TAG))
2605 {
2606 BCM_LOG(INFO, log_id_sw_util, " flow %d upstream/downstream outer vlan translation not symmetrical \n", p_flow->key.flow_id );
2607 ret = BCMOS_FALSE;
2608 }
2609
2610 }
2611
2612 return ret;
2613}
2614
2615#endif /* #ifndef TEST_SW_UTIL_LOOPBACK */
2616
2617/*@}*/
2618