目的入口(dst_entry)

本文深入解析了IP数据报路由中的目的入口(dst_entry)结构及其作用,包括其内部字段的含义和工作原理,如__refcnt、__use、dev、flags等,并通过实例展示了目的入口在不同场景下的应用。
部署运行你感兴趣的模型镜像
最终生成的IP数据报的路由称为目的入口(dst_entry),目的入口反映了相邻的外部主机在主机内部的一种“映象”,目的入口在内核中的定义如下:
    struct dst_entry
    {
        struct dst_entry        *next;
        atomic_t    __refcnt;
        int         __use;
        struct dst_entry    *child;
        struct net_device   *dev;
        short   error;
        short   obsolete;
        int     flags;
#define DST_HOST        1
#define DST_NOXFRM      2
#define DST_NOPOLICY    4
#define DST_NOHASH      8
#define DST_BALANCED    0x10
        unsigned long   lastuse;
        unsigned long   expires;
        unsigned short  header_len;
        unsigned short  trailer_len;
        u32         metrics[RTAX_MAX];
        struct dst_entry    *path;
        unsigned long       rate_last;
        unsigned long       rate_tokens;
        struct neighbour    *neighbour;
        struct hh_cache     *hh;
        struct xfrm_state   *xfrm;
        int         (*input)(struct sk_buff*);
        int         (*output)(struct sk_buff*);
#ifdef CONFIG_NET_CLS_ROUTE
        __u32           tclassid;
#endif
        struct  dst_ops         *ops;
        struct rcu_head     rcu_head;
        char            info[0];
    };
    __refcnt是目的入口的引用计数,创建成功后即设为1。__use是一个统计数值,该目的入口被使用一次(发送一个IP数据报),__use就加1。
    dev是该路由的输出网络设备接口,flags是标志位,其取值可以是DST_HOST,DST_NOXFRM,DST_NOPOLICY,DST_NOHASH,DST_BALANCED(用在路由有多路径的情况下)。
    lastuse是一个时间值,每次目的入口被用于发送IP数据报,就将该值设置为当前系统时间值。该值被用于几个地方,路由缓存表 myrt_hash_table是一个很大的数组(依据系统的内存大小而定),每一项都是一个struct rtable的链表,当要往缓存表的某一个链表中插入一个新的struct rtable时,如果这个链表的长度已经超出ip_rt_gc_elasticity(值为8),则需要删掉一个当前使用价值最低的,已保持链表长度的平 衡。函数rt_score就是用于为每个struct rtable计算价值分数,分数是一个32位值,最高位表示非常有价值,当struct rtable的成员rt_flags上有标志RTCF_REDIRECTED或RTCF_NOTIFY,或者目的入口的超时时间未到时,置该位,次高位价 值次之,余下的30位由lastuse决定,该目的入口距上次使用时间越长,价值越低。另外,用于在rt_may_expire函数中判断一个 struct rtable是否超时。
    expires是一个超时时间值,定时器rt_periodic_timer定期扫描路由缓存表rt_hash_table,如果发现expires值为0,或者小于当前系统时间值,并符合其它超时条件,则把该路由从缓存表中删除。
    neighbour是为该路由绑定的邻居节点,详细分析见arp部分。
    hh是硬件头缓存,ARP解析得到的邻居的mac地址缓存在这里,再次发送IP数据报的时候,就不需要再到ARP缓存中去取硬件头。
    input和output分别是该目的入口的输入和输出函数。

    前面讲到通过在一张路由表(struct fib_table)中,根据查询路由的目的IP地址(key)在其路由哈希表(struct fn_hash)中找到一个路由域(struct fn_zone),并在路由域中匹配到一个key相等的路由节点(struct fib_node),取其路由别名(struct fib_alias)和路由信息(struct fib_info),生成一个路由查询结果(struct fib_result)。
    路由查询结果还不能直接供发送IP数据报使用,接下来,还必须根据这个查询结果生成一个路由目的入口(dst_entry),根据目的入口才可以发送IP 数据报,目的入口用结构体struct dst_entry表示,在实际使用时,还在它的外面包装了一层,形成一个结构体struct rtable。struct rtable的定义如下:
    struct rtable
    {
        union{
            struct dst_entry    dst;
            struct rtable       *rt_next;
        }u;
        struct in_device    *idev;
        unsigned    rt_flags;
        __u16       rt_type;
        __u16       rt_multipath_alg;
        __u32       rt_dst;
        __u32       rt_src;
        int         rt_iif;
        __u32           rt_gateway;
        struct flowi    fl;
        __u32           rt_spec_dst;
        struct inet_peer    *peer;
    };
    rt_flags是一组标志位,按目的入口查询的执行顺序:如果路由使用本地环回接口,则rt_flags上加标志RTCF_LOCAL,如果路由结果类 型是广播,则加标志RTCF_BROADCAST和RTCF_LOCAL,如果结果是组播,则加标志RTCF_MULTICAST和 RTCF_LOCAL,该标志最终决定了目的入口使用哪一个IP数据报输入函数和输出函数,如果是RTCF_LOCAL,则使用输入函数 ip_local_deliver,如果是RTCF_BROADCAST或RTCF_MULTICAST,并且带有RTCF_LOCAL标志,并且输出设 备不是环回接口设备,则使用输出函数ip_mc_output,否则使用输出函数ip_output。
    rt_type是路由类型,如果路由是LOOPBACK,则置类型为RTN_LOCAL,单播路由类型为RTN_UNICAST,如果目的地址为 0xFFFFFFFF,则路由类型为RTN_BROADCAST,如果目的地址是组播地址,则路由类型为RTN_MULTICAST。rt_type跟 rt_flags关系比较密切。
    rt_multipath_alg跟路由多路径相关,暂时略过。rt_dst是路由的目的地址,rt_src是路由的源地址,rt_iif是路由的输入设备接口的索引号。rt_gateway是路由网关的IP地址。
    在试验环境中,网络设备接口mylo的IP地址是127.10.0.1,它在内核中的表示是struct net_device myloopback_dev,测试程序往IP地址127.10.0.1发送DUMMY协议的数据报,协议栈为其生成的路由目的入口如下:
    the dst_entry:
        the dev name: mylo
        the error: 0
        the obsolete: 0
        the flag: DST_HOST
        expires: 0, now: 110343
        header len: 0
    rt_flag: RTCF_LOCAL
    rt_type: RTN_LOCAL
    rt_dst: 127.10.0.1
    rt_src: 127.10.0.1
    rt_iif: 4
    rt_gateway: 127.10.0.1
    rt_spec_dst: 127.10.0.1
    试验环境中的网络设备接口eth0的IP地址是172.16.48.2,测试程序往该IP地址所在子网内的IP地址172.16.48.1发送DUMMY协议的数据报,协议栈为其生成的路由目的入口如下:
    the dst_entry:
        the dev name: eth0
        the error: 0
        the obsolete: 0
        the flag: DST_HOST
        expires: 0, now: 850858
        header len: 0
    rt_flag: 0
    rt_type: RTN_UNICAST
    rt_dst: 172.16.48.1
    rt_src: 172.16.48.2
    rt_iif: 2
    rt_gateway: 172.16.48.1
    rt_spec_dst: 172.16.48.2

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

static INT32 _dalTrafficPacketMapFind(int port_idx, int packet_idx) { int i; for (i = 0; i < MAX_TRAFFIC_PACKET_MAP; i++) { if (g_trafficPacketMap[i].port_idx == port_idx && g_trafficPacketMap[i].packet_idx == packet_idx) { printf("[MAP_FIND] Found ID:%u at index:%d\n", g_trafficPacketMap[i].packetId, i); return g_trafficPacketMap[i].packetId; } } return INVALID_PACKET_ID; } // 移除映射 static void _dalTrafficPacketMapRemove(int port_idx, int packet_idx) { int i; for (i = 0; i < MAX_TRAFFIC_PACKET_MAP; i++) { if (g_trafficPacketMap[i].port_idx == port_idx && g_trafficPacketMap[i].packet_idx == packet_idx) { printf("[MAP_REMOVE] Removing ID:%u at index:%d\n", g_trafficPacketMap[i].packetId, i); g_trafficPacketMap[i].port_idx = 0; g_trafficPacketMap[i].packet_idx = 0; g_trafficPacketMap[i].packetId = INVALID_PACKET_ID; // 设为无效标识 return; } } } // 添加映射 static int _dalTrafficPacketMapAdd(int port_idx, int packet_idx, UINT32 packetId) { int i; // 先检查是否已经存在,如果存在则更新 for (i = 0; i < MAX_TRAFFIC_PACKET_MAP; i++) { if (g_trafficPacketMap[i].port_idx == port_idx && g_trafficPacketMap[i].packet_idx == packet_idx) { printf("[MAP_ADD] Updating existing entry at index:%d (old ID:%u)\n", i, g_trafficPacketMap[i].packetId); g_trafficPacketMap[i].packetId = packetId; return ERR_NO_ERROR; } } // 不存在,则找一个空位 for (i = 0; i < MAX_TRAFFIC_PACKET_MAP; i++) { if (g_trafficPacketMap[i].packetId == INVALID_PACKET_ID) // 检查无效标识 { printf("[MAP_ADD] Adding to empty slot:%d\n", i); g_trafficPacketMap[i].port_idx = port_idx; g_trafficPacketMap[i].packet_idx = packet_idx; g_trafficPacketMap[i].packetId = packetId; return ERR_NO_ERROR; } } return ERR_NO_MEMORY; } static int _dalDmpTrafficTestHandler(dal_ado_t *adoi, dal_attr *attr) { void *handler = NULL; char *key = NULL; int upIdx = 0; int packetIdx = -1; user_port up = {}; UINT16 speed = 0; UINT8 enable = 0; UINT32 packetId = 0; UINT32 oldPacketId = -1; char rawPacket[MAX_PAYLOAD_LEN] = {0}; char srcMac[MAC_LEN] ={0}; char dstMac[MAC_LEN] ={0}; char srcIp[IPv4_LEN] = {0}; char dstIp[IPv4_LEN] = {0}; UINT16 lenType = 0; UINT8 vlan = 0; DAL_ADOI_OPTION_LOOP(adoi) { if (NULL == (key = DAL_ADOI_OPTION_KEY(adoi))) { break; } if (STR_EQUAL(key, DAL_TRAFFIC_TEST_GLOBLE)) { if (DAL_ADOI_OPTION_FIELD_MATCH(adoi, DAL_TRAFFIC_TEST_TX_SPEED)) { dalAdoiGetOptionUI16(adoi, &speed); printf("hiTrafficTestSpeedSet[%d]", speed); if(0 != speed) { APPL_IF_ERR_RET(hiTrafficTestSpeedSet(speed)); } } else if(DAL_ADOI_OPTION_FIELD_MATCH(adoi, DAL_TRAFFIC_TEST_ENABLE)) { dalAdoiGetOptionUI8(adoi, &enable); printf("hiTrafficTestEnableSet[%d]", enable); } } } if (NULL != (handler = DAL_ADOI_ENTRY(adoi, DAL_TRAFFIC_TEST_PORT_TBL))) { DAL_ADOI_ENTRY_LOOP(handler) { if (NULL== (key = DAL_ADOI_ENTRY_KEY(handler)) || !DAL_ADOI_ENTRY_KEY_MATCH(handler, DAL_TRAFFIC_TEST_PORT_TBL_ALL)) { continue; } if (DAL_ADOI_ENTRY_KEY_EMPTY(handler)) { sscanf(key, DAL_TRAFFIC_TEST_PORT_TBL_FMT, &upIdx, &packetIdx); printf("Stopping traffic on port %d, packet %d\n", upIdx, packetIdx); oldPacketId = _dalTrafficPacketMapFind(upIdx, packetIdx); if (oldPacketId != INVALID_PACKET_ID) { printf("Stopping packet: port=%d, packet=%d, ID=%u\n", upIdx, packetIdx, oldPacketId); APPL_IF_ERR_RET(hiTrafficTestPacketRemove(oldPacketId)); _dalTrafficPacketMapRemove(upIdx, packetIdx); } } else { sscanf(key, DAL_TRAFFIC_TEST_PORT_TBL_FMT, &upIdx, &packetIdx); UP_FROM_IDX(up, upIdx); if (UNIT_CURRENT != UP_UNIT(up)) { continue; } DAL_ADOI_ENTRY_FIELD_LOOP(handler, key) { if (DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_RAW_PACKET)) { dalAdoiGetEntryStr(adoi, DAL_TRAFFIC_TEST_PORT_TBL, rawPacket, MAX_PAYLOAD_LEN); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_SRC_MAC)) { dalAdoiGetEntryStr(adoi, DAL_TRAFFIC_TEST_PORT_TBL, srcMac, MAC_LEN); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_DST_MAC)) { dalAdoiGetEntryStr(adoi, DAL_TRAFFIC_TEST_PORT_TBL, dstMac, MAC_LEN); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_SRC_IP)) { dalAdoiGetEntryStr(adoi, DAL_TRAFFIC_TEST_PORT_TBL, srcIp, IPv4_LEN); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_DST_IP)) { dalAdoiGetEntryStr(adoi, DAL_TRAFFIC_TEST_PORT_TBL, dstIp, IPv4_LEN); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_LENTYPE)) { dalAdoiGetEntryUI16(adoi, DAL_TRAFFIC_TEST_PORT_TBL, &lenType); } else if(DAL_ADOI_ENTRY_FIELD_MATCH(handler, DAL_TRAFFIC_TEST_PORT_VLAN)) { dalAdoiGetEntryUI8(adoi, DAL_TRAFFIC_TEST_PORT_TBL, &vlan); } else { printf("Invalid field %s !", DAL_ADOI_ENTRY_FIELD(handler)); } } oldPacketId = _dalTrafficPacketMapFind(upIdx, packetIdx); if (oldPacketId != INVALID_PACKET_ID) { printf("Replacing packet: port=%d, packet=%d\n", upIdx, packetIdx); APPL_IF_ERR_RET(hiTrafficTestPacketRemove(oldPacketId)); _dalTrafficPacketMapRemove(upIdx, packetIdx); } APPL_IF_ERR_RET(hiTrafficTestPacketSet(up, rawPacket, srcMac, dstMac, srcIp, dstIp, lenType, vlan, &packetId)); _dalTrafficPacketMapAdd(upIdx, packetIdx, packetId); } } printf("Calling hiTrafficTestPacketSet with:\n"); printf(" rawPacket: %s\n", rawPacket); printf(" srcMac: %s\n", srcMac); printf(" dstMac: %s\n", dstMac); printf(" srcIp: %s\n", srcIp); printf(" dstIp: %s\n", dstIp); printf(" lenType: %d\n", lenType); printf(" vlan: %d\n", vlan); } return ERR_NO_ERROR; } 在这里加上else if(DAL_ADOI_OPTION_FIELD_MATCH(adoi, DAL_TRAFFIC_TEST_ENABLE)) { dalAdoiGetOptionUI8(adoi, &enable); printf("hiTrafficTestEnableSet[%d]", enable); } enable为0时遍历映射表,关闭所有发包并清空映射表
最新发布
11-04
dad检测报文应该从以下代码中的那一条分支发送:netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); struct net_bridge_fdb_entry *dst; struct net_bridge_mdb_entry *mdst; struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats); const struct nf_br_ops *nf_ops; const unsigned char *dest; struct ethhdr *eth; u16 vid = 0; struct ipv6hdr *my_ip6h = ipv6_hdr(skb); struct icmp6hdr *icmp6h = icmp6_hdr(skb); if ((icmp6h->icmp6_type) == NDISC_NEIGHBOUR_SOLICITATION) { printk(KERN_INFO "%s %s %d: saddr:%pI6c daddr: %pI6c skbname:%s\n", __FILE__, __FUNCTION__, __LINE__, &(my_ip6h->saddr), &(my_ip6h->daddr), skb->dev->name); } #if defined(CONFIG_TP_HOMESHIELD) int (*block_xmit)(struct sk_buff *skb) = NULL; #endif #if defined(CONFIG_TP_HOMESHIELD) block_xmit = rcu_dereference(blocking_xmit); if (block_xmit && block_xmit(skb)) { kfree_skb(skb); return NETDEV_TX_OK; } #endif rcu_read_lock(); nf_ops = rcu_dereference(nf_br_ops); if (nf_ops && nf_ops->br_dev_xmit_hook(skb)) { rcu_read_unlock(); return NETDEV_TX_OK; } u64_stats_update_begin(&brstats->syncp); brstats->tx_packets++; brstats->tx_bytes += skb->len; u64_stats_update_end(&brstats->syncp); br_switchdev_frame_unmark(skb); BR_INPUT_SKB_CB(skb)->brdev = dev; BR_INPUT_SKB_CB(skb)->frag_max_size = 0; skb_reset_mac_header(skb); eth = eth_hdr(skb); skb_pull(skb, ETH_HLEN); if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid)) goto out; if (IS_ENABLED(CONFIG_INET) && (eth->h_proto == htons(ETH_P_ARP) || eth->h_proto == htons(ETH_P_RARP)) && br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) { br_do_proxy_suppress_arp(skb, br, vid, NULL); } else if (IS_ENABLED(CONFIG_IPV6) && skb->protocol == htons(ETH_P_IPV6) && br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) && pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)) && ipv6_hdr(skb)->nexthdr == IPPROTO_ICMPV6) { struct nd_msg *msg, _msg; msg = br_is_nd_neigh_msg(skb, &_msg); if (msg) br_do_suppress_nd(skb, br, vid, NULL, msg); } dest = eth_hdr(skb)->h_dest; if (is_broadcast_ether_addr(dest)) { br_flood(br, skb, BR_PKT_BROADCAST, false, true); } else if (is_multicast_ether_addr(dest)) { if (unlikely(netpoll_tx_running(dev))) { br_flood(br, skb, BR_PKT_MULTICAST, false, true); goto out; } if (br_multicast_rcv(br, NULL, skb, vid)) { kfree_skb(skb); goto out; } if ((icmp6h->icmp6_type) == NDISC_NEIGHBOUR_SOLICITATION) { printk(KERN_INFO "%s %s %d: saddr:%pI6c daddr: %pI6c skbname:%s\n", __FILE__, __FUNCTION__, __LINE__, &(my_ip6h->saddr), &(my_ip6h->daddr), skb->dev->name); } mdst = br_mdb_get(br, skb, vid); if (NULL == mdst) { printk(KERN_INFO "mdst is null %s %s %d: saddr:%pI6c daddr: %pI6c skbname:%s\n", __FILE__, __FUNCTION__, __LINE__, &(my_ip6h->saddr), &(my_ip6h->daddr), skb->dev->name); } if ((mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) && br_multicast_querier_exists(br, eth_hdr(skb))) br_multicast_flood(mdst, skb, false, true); else br_flood(br, skb, BR_PKT_MULTICAST, false, true); } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { br_forward(dst->dst, skb, false, true); } else { br_flood(br, skb, BR_PKT_UNICAST, false, true); } out: rcu_read_unlock(); return NETDEV_TX_OK; }
10-28
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值