📄 dev_nm_16esw.c
字号:
} p->egress_bitmap = 1 << egress_port; p->egress_ut_bitmap = p->vlan_entry[2] & BCM5600_VTABLE_UT_PORT_BMAP_MASK; } else { /* Multicast: send the packet to the egress ports found in MARL table */ p->egress_bitmap = arl_entry[2] & BCM5600_MARL_PORT_BMAP_MASK; p->egress_ut_bitmap = arl_entry[3] & BCM5600_MARL_UT_PORT_BMAP_MASK; }#if DEBUG_FORWARD { char buffer[1024]; BCM_LOG(d,"bitmap: 0x%8.8x, filter: 0x%8.8x\n", p->egress_bitmap,p->egress_filter_bitmap); bcm5600_port_bitmap_str(d,buffer,p->egress_bitmap); /* without egress port filtering */ if (*buffer) BCM_LOG(d,"forwarding to egress port list w/o filter: %s\n",buffer); else BCM_LOG(d,"w/o filter: empty egress port list.\n"); /* with egress port filtering */ bcm5600_port_bitmap_str(d,buffer, p->egress_bitmap & ~p->egress_filter_bitmap); if (*buffer) BCM_LOG(d,"forwarding to egress port list w/ filter: %s\n",buffer); }#endif return(p->egress_bitmap != 0);}/* Prototype for a packet sending function */typedef void (*bcm5600_send_pkt_t)(struct nm_16esw_data *d, struct bcm5600_pkt *p, netio_desc_t *nio);/* Directly forward a packet (not rewritten) */static void bcm5600_send_pkt_direct(struct nm_16esw_data *d, struct bcm5600_pkt *p, netio_desc_t *nio){ netio_send(nio,p->pkt,p->pkt_len);}/* Send a packet with a 802.1Q tag */static void bcm5600_send_pkt_push_dot1q(struct nm_16esw_data *d, struct bcm5600_pkt *p, netio_desc_t *nio){ n_eth_dot1q_hdr_t *hdr; if (!p->rewrite_done) { memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2)); hdr = (n_eth_dot1q_hdr_t *)p->rewr_pkt; hdr->type = htons(N_ETH_PROTO_DOT1Q); hdr->vlan_id = htons(p->real_vlan); memcpy(p->rewr_pkt + sizeof(n_eth_dot1q_hdr_t), p->pkt + (N_ETH_HLEN - 2), p->pkt_len - (N_ETH_HLEN - 2)); p->rewrite_done = TRUE; } netio_send(nio,p->rewr_pkt,p->pkt_len+4);}/* Send a packet deleting its 802.1Q tag */static void bcm5600_send_pkt_pop_dot1q(struct nm_16esw_data *d, struct bcm5600_pkt *p, netio_desc_t *nio){ if (!p->rewrite_done) { memcpy(p->rewr_pkt,p->pkt,(N_ETH_HLEN - 2)); memcpy(p->rewr_pkt + (N_ETH_HLEN - 2), p->pkt + sizeof(n_eth_dot1q_hdr_t), p->pkt_len - sizeof(n_eth_dot1q_hdr_t)); p->rewrite_done = TRUE; } netio_send(nio,p->rewr_pkt,p->pkt_len-4);}/* Forward a packet on physical ports (egress bitmap must be defined) */static int bcm5600_forward_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p){ u_char rewr_pkt[BCM5600_MAX_PKT_SIZE]; bcm5600_send_pkt_t send_pkt; u_int egress_untagged,trunk_id; m_uint32_t *dst_port,*trunk; int i; p->egress_bitmap &= ~p->egress_filter_bitmap; if (!p->egress_bitmap) return(FALSE); /* Process egress mirroring (if enabled) */ if (p->egress_bitmap & d->mirror_egress_ports) bcm5600_mirror_pkt(d,p,1); /* No rewrite done at this time */ p->rewr_pkt = rewr_pkt; p->rewrite_done = FALSE; /* Forward to CPU port ? */ if (p->egress_bitmap & (1 << d->cpu_port)) bcm5600_send_pkt_to_cpu(d,p); for(i=0;i<d->nr_port;i++) { if (!(p->egress_bitmap & (1 << i))) continue; /* * If this port is a member of a trunk, remove all other ports to avoid * duplicate frames (typically, when a dest MAC address is unknown * or for a broadcast/multicast). */ dst_port = bcm5600_table_get_entry(d,d->t_ptable,i); assert(dst_port != NULL); if (dst_port[0] & BCM5600_PTABLE_TRUNK_FLAG) { trunk_id = dst_port[0] & BCM5600_PTABLE_TGID_MASK; trunk_id >>= BCM5600_PTABLE_TGID_SHIFT; trunk = bcm5600_table_get_entry(d,d->t_tbmap,trunk_id); assert(trunk != NULL); p->egress_bitmap &= ~trunk[0]; } /* select the appropriate output vector */ if (p->orig_vlan == 0) send_pkt = bcm5600_send_pkt_direct; else { egress_untagged = p->egress_ut_bitmap & (1 << i); if (p->orig_vlan == -1) { /* Untagged packet */ if (egress_untagged) send_pkt = bcm5600_send_pkt_direct; else send_pkt = bcm5600_send_pkt_push_dot1q; } else { /* Tagged packet */ if (egress_untagged) send_pkt = bcm5600_send_pkt_pop_dot1q; else send_pkt = bcm5600_send_pkt_direct; } }#if DEBUG_FORWARD > 1 BCM_LOG(d,"forwarding on port %s (vector=%p)\n", d->ports[i].name,send_pkt);#endif send_pkt(d,p,d->ports[i].nio); } return(TRUE);}/* Handle a received packet */static int bcm5600_handle_rx_pkt(struct nm_16esw_data *d,struct bcm5600_pkt *p){ m_uint32_t *port_entry; n_eth_dot1q_hdr_t *eth_hdr; u_int discard; /* No egress port at this time */ p->egress_bitmap = 0; /* Never send back frames to the source port */ p->egress_filter_bitmap = 1 << p->ingress_port; if (!(port_entry = bcm5600_table_get_entry(d,d->t_ptable,p->ingress_port))) return(FALSE); /* Analyze the Ethernet header */ eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt; /* Check for the reserved addresses (BPDU for spanning-tree) */ if (!memcmp(ð_hdr->daddr,"\x01\x80\xc2\x00\x00",5) || !memcmp(ð_hdr->daddr,"\x01\x00\x0c\xcc\xcc\xcd",6)) {#if DEBUG_RECEIVE BCM_LOG(d,"Received a BPDU packet:\n"); mem_dump(d->vm->log_fd,p->pkt,p->pkt_len);#endif p->orig_vlan = 0; p->egress_bitmap |= 1 << d->cpu_port; return(bcm5600_forward_pkt(d,p)); } /* Discard packet ? */ discard = port_entry[0] & BCM5600_PTABLE_PRT_DIS_MASK; discard >>= BCM5600_PTABLE_PRT_DIS_SHIFT; if (discard) { if (discard != 0x20) { printf("\n\n\n" "-----------------------------------------------------------" "---------------------------------\n" "Unspported feature: please post your current configuration " "on http://www.ipflow.utc.fr/blog/\n" "-----------------------------------------------------------" "---------------------------------\n"); } /* Drop the packet */ return(FALSE); } /* Mirroring on Ingress ? */ if (port_entry[1] & BCM5600_PTABLE_MI_FLAG) bcm5600_mirror_pkt(d,p,0); /* Determine VLAN */ if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) { p->orig_vlan = -1; p->real_vlan = port_entry[0] & BCM5600_PTABLE_VLAN_TAG_MASK; if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) return(FALSE); /* TODO: 802.1p/CoS remarking */ if (port_entry[4] & BCM5600_PTABLE_RPE_FLAG) { } } else { p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF; /* Check that this VLAN exists */ if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) return(FALSE); /* Check that this port is a member of this VLAN */ if (!(p->vlan_entry[1] & (1 << p->ingress_port))) return(FALSE); }#if DEBUG_RECEIVE BCM_LOG(d,"%s: received a packet on VLAN %u\n", d->ports[p->ingress_port].name,p->real_vlan);#endif /* Source MAC address learning */ if (!bcm5600_src_mac_learning(d,p)) return(FALSE); /* Take forwarding decision based on destination MAC address */ if (!bcm5600_dst_mac_lookup(d,p)) return(FALSE); /* Send the packet to the egress ports */ return(bcm5600_forward_pkt(d,p));}/* Handle a packet to transmit */static int bcm5600_handle_tx_pkt(struct nm_16esw_data *d, struct bcm5600_pkt *p, u_int egress_bitmap){ n_eth_dot1q_hdr_t *eth_hdr; /* Never send back frames to the source port */ p->egress_filter_bitmap = 1 << p->ingress_port; /* We take the complete forwarding decision if bit 23 is set */ if (egress_bitmap & (1 << 23)) { /* No egress port at this time */ p->egress_bitmap = 0; /* The packet must be tagged so that we can determine the VLAN */ eth_hdr = (n_eth_dot1q_hdr_t *)p->pkt; if (ntohs(eth_hdr->type) != N_ETH_PROTO_DOT1Q) { BCM_LOG(d,"bcm5600_handle_tx_pkt: untagged packet ?\n"); return(FALSE); } /* Find the appropriate, check it exists (just in case) */ p->orig_vlan = p->real_vlan = ntohs(eth_hdr->vlan_id) & 0xFFF; if (!(p->vlan_entry = bcm5600_vtable_get_entry_by_vlan(d,p->real_vlan))) return(FALSE);#if DEBUG_TRANSMIT BCM_LOG(d,"Transmitting a packet from TX ring to VLAN %u\n", p->real_vlan);#endif /* Take forwarding decision based on destination MAC address */ if (!bcm5600_dst_mac_lookup(d,p)) return(FALSE); } else {#if DEBUG_TRANSMIT BCM_LOG(d,"Transmitting natively a packet from TX ring.\n");#endif /* The egress ports are specified, send the packet natively */ p->orig_vlan = 0; p->egress_bitmap = egress_bitmap; } /* Send the packet to the egress ports */ return(bcm5600_forward_pkt(d,p));}/* Handle the TX ring */static int dev_bcm5600_handle_txring(struct nm_16esw_data *d){ struct bcm5600_pkt pkt_data; m_uint32_t tdes[4],txd_len; BCM_LOCK(d); if (!d->tx_current || d->tx_end_scan) { BCM_UNLOCK(d); return(FALSE); } /* Read the current TX descriptor */ physmem_copy_from_vm(d->vm,tdes,d->tx_current,4*sizeof(m_uint32_t)); tdes[0] = vmtoh32(tdes[0]); tdes[1] = vmtoh32(tdes[1]); tdes[2] = vmtoh32(tdes[2]); tdes[3] = vmtoh32(tdes[3]); #if DEBUG_TRANSMIT BCM_LOG(d,"=== TRANSMIT PATH ===\n"); BCM_LOG(d,"tx_current=0x%8.8x, " "tdes[0]=0x%8.8x, tdes[1]=0x%8.8x, tdes[2]=0x%8.8x\n", d->tx_current,tdes[0],tdes[1],tdes[2]);#endif /* Get the buffer size */ txd_len = tdes[1] & 0x7FF; /* Check buffer size */ if ((d->tx_bufsize + txd_len) >= sizeof(d->tx_buffer)) goto done; /* Copy the packet from memory */ physmem_copy_from_vm(d->vm,d->tx_buffer+d->tx_bufsize,tdes[0],txd_len); d->tx_bufsize += txd_len; /* Packet not complete: handle it later */ if (tdes[1] & BCM5600_TXD_NEOP) goto done;#if DEBUG_TRANSMIT mem_dump(d->vm->log_fd,d->tx_buffer,d->tx_bufsize);#endif /* Transmit the packet */ pkt_data.ingress_port = d->cpu_port; pkt_data.pkt = d->tx_buffer; pkt_data.pkt_len = d->tx_bufsize - 4; pkt_data.sent_to_cpu = TRUE; bcm5600_handle_tx_pkt(d,&pkt_data,tdes[2]); /* Reset the TX buffer (packet fully transmitted) */ d->tx_bufsize = 0; done: /* We have reached end of ring: trigger the TX underrun interrupt */ if (!(tdes[1] & BCM5600_TXD_RING_CONT)) { d->tx_end_scan = 1; pci_dev_trigger_irq(d->vm,d->pci_dev); BCM_UNLOCK(d); return(TRUE); } /* Go to the next descriptor */ d->tx_current += BCM5600_TXD_SIZE; BCM_UNLOCK(d); return(TRUE);}/* Handle the RX ring */static int dev_bcm5600_handle_rxring(netio_desc_t *nio, u_char *pkt,ssize_t pkt_len, struct nm_16esw_data *d, struct bcm5600_port *port){ struct bcm5600_pkt pkt_data; m_uint32_t rxd_len;#if DEBUG_RECEIVE BCM_LOG(d,"=== RECEIVE PATH ===\n"); BCM_LOG(d,"%s: received a packet of %ld bytes.\n", port->name,(u_long)pkt_len); mem_dump(d->vm->log_fd,pkt,pkt_len);#endif BCM_LOCK(d); if (!d->rx_current || d->rx_end_scan) { BCM_UNLOCK(d); return(FALSE); } /* Read the current TX descriptor */ physmem_copy_from_vm(d->vm,pkt_data.rdes,d->rx_current, (4 * sizeof(m_uint32_t))); pkt_data.rdes[0] = vmtoh32(pkt_data.rdes[0]); pkt_data.rdes[1] = vmtoh32(pkt_data.rdes[1]); pkt_data.rdes[2] = vmtoh32(pkt_data.rdes[2]); pkt_data.rdes[3] = vmtoh32(pkt_data.rdes[3]);#if DEBUG_RECEIVE BCM_LOG(d,"rx_current=0x%8.8x, " "rdes[0]=0x%8.8x, rdes[1]=0x%8.8x, rdes[2]=0x%8.8x\n", d->rx_current,pkt_data.rdes[0],pkt_data.rdes[1],pkt_data.rdes[2]);#endif /* Get the buffer size */ rxd_len = pkt_data.rdes[1] & 0x7FF; if (pkt_len > rxd_len) { BCM_UNLOCK(d); return(FALSE); } /* Fill the packet info */ pkt_data.ingress_port = port->id; pkt_data.pkt = pkt; pkt_data.pkt_len = pkt_len; pkt_data.sent_to_cpu = FALSE; /* Handle the packet */ bcm5600_handle_rx_pkt(d,&pkt_data); /* Signal only an interrupt when a packet has been sent to the CPU */ if (pkt_data.sent_to_cpu) { /* We have reached end of ring: trigger the RX underrun interrupt */ if (!(pkt_data.rdes[1] & BCM5600_RXD_RING_CONT)) { d->rx_end_scan = 1; pci_dev_trigger_irq(d->vm,d->pci_dev); BCM_UNLOCK(d); return(TRUE); } /* A packet was received */ pci_dev_trigger_irq(d->vm,d->pci_dev); /* Go to the next descriptor */ d->rx_current += BCM5600_RXD_SIZE; } BCM_UNLOCK(d); return(TRUE);}/* pci_bcm5605_read() */static m_uint32_t pci_bcm5605_read(cpu_mips_t *cpu,s
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -