Bird with STL Filter mode

29 views
Skip to first unread message

Haklat haklat

unread,
Jul 2, 2024, 3:57:10 AMJul 2
to TRex Traffic Generator
Hi,
I am working with Bird using BFD in different ways:

- Static route with BFD
- BGP with BFD
- OSPF with BFD

Would like to, if possible, explore using this in service filtered mode. The RX filters available does not cover for BFD I think. Where in the code are those, already existing  filters defined. Would like to understand if it would be possible to define some new RX filter combinations:

- bfd (UDP ports 3784-3785 filtered to RX)
- bgp_bfd
- no_tcp_udp_except_bfd

Thanks//Håkan

hanoh haim

unread,
Jul 2, 2024, 6:12:32 AMJul 2
to Haklat haklat, TRex Traffic Generator
Hi Haklat, 
There are two places in c++ server code, this is the first instance (case of single and multi-core), in case of multi-core there is a redirect from DP->RX

https://github.com/cisco-system-traffic-generator/trex-core/blob/61fb7aead7063d98bf16cd9392e85021193d5584/src/44bsd/flow_table.cpp#L278



Look for the client Python code too, in case of BGP look for BGP_MASK and add another mask 

Thanks
Hanoh


--
You received this message because you are subscribed to the Google Groups "TRex Traffic Generator" group.
To unsubscribe from this group and stop receiving emails from it, send an email to trex-tgn+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/trex-tgn/8e871b12-593f-4f60-802e-d62567cb8941n%40googlegroups.com.


--
Hanoh
Sent from my iPhone

Haklat haklat

unread,
Jul 3, 2024, 8:12:03 AMJul 3
to TRex Traffic Generator
Hi Hanoh,

thanks alot. This was fun. Think I got it working:

    // enum for m_service_mask
    enum service_filter {
        SERVICE_OFF  = 0,
        NO_TCP_UDP   = 1,
        BGP          = 1 << 1,
        DHCP         = 1 << 2, /* both for v4 and v6 */
        TRANSPORT    = 1 << 3, /* TCP & UDP with source (port& 0xff00 == 0xff00) generated by EMU */
        MDNS         = 1 << 4,  /* mDNS - multicast DNS - EMU */
        BFD          = 1 << 5  /* all BFD ports */   #### Added BFD as 6th bit (32)
    };

Some v.3.05 testing on i40e SRIOV - """./t-rex-64 -i -c 2 --software --bird-server"""
c.set_service_mode(ports = [0], enabled = False, filtered = True, mask = 1)

Works as expected - OSPF comes up but BFD stays Down:
bird> show pro
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     11:20:51.049  
my_bfd1    BFD        ---        up     11:20:51.049  
my_ospfv4  OSPF       master4    up     11:20:51.049  Running
my_ospfv6  OSPF       master6    up     11:20:51.049  Running
bird_cfg_routes Static     master4    up     11:20:51.049  
bird> show bfd session
my_bfd1:
IP address                Interface  State      Since         Interval  Timeout
fe80::250:56ff:fe30:309   bird-0-2-L Down       11:31:33.454    1.000    0.000  ### IPv6 BFD Down as filer is now only for OSPF
172.80.39.50              bird-0-2-L Down       11:31:21.625    1.000    0.000          ### IPv4 BFD Down as filer is now only for OSPF


c.set_service_mode(ports = [0], enabled = False, filtered = True, mask = 32)  Allows BFD ports 3784, 3784 & 4784

Not sure why OSPFv3 (IPv6) get OSPF connected but might be due to IPv6 mcast different from IPv4 somehow. Looks probably kind of expected.
bird> show pro
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     11:20:51.049  
my_bfd1    BFD        ---        up     11:20:51.049  
my_ospfv4  OSPF       master4    up     11:20:51.049  Alone
my_ospfv6  OSPF       master6    up     11:20:51.049  Running
bird_cfg_routes Static     master4    up     11:20:51.049  
bird> show bfd session
my_bfd1:
IP address                Interface  State      Since         Interval  Timeout
fe80::250:56ff:fe30:309   bird-0-3-L Up         11:36:54.391    1.000    3.000
172.80.39.50              bird-0-3-L Init       11:37:12.577    1.000    3.000
bird>
bird> show ospf neig
my_ospfv4:
Router ID       Pri          State      DTime   Interface  Router IP
172.80.39.50      1     ExStart/BDR     38.584  bird-0-3-L 172.80.39.50

my_ospfv6:
Router ID       Pri          State      DTime   Interface  Router IP
172.80.39.50      1     Full/DR         37.851  bird-0-3-L fe80::250:56ff:fe30:309
bird>


c.set_service_mode(ports = [0], enabled = False, filtered = True, mask = 33) ### This mask is for OSPF with BFD

With this filter all works as expected:
[root@trex-intel-trex-bfd-1-1 bird]# ./birdcl -s /tmp/trex-bird/bird.ctl
BIRD 2.0.8 ready.
bird> show pro
Name       Proto      Table      State  Since         Info
device1    Device     ---        up     11:20:51.049  
my_bfd1    BFD        ---        up     11:20:51.049  
my_ospfv4  OSPF       master4    up     11:20:51.049  Running
my_ospfv6  OSPF       master6    up     11:20:51.049  Running
bird_cfg_routes Static     master4    up     11:20:51.049  
bird> show ospf neig
my_ospfv4:
Router ID       Pri          State      DTime   Interface  Router IP
172.80.39.50      1     Full/DR         35.613  bird-0-4-L 172.80.39.50

my_ospfv6:
Router ID       Pri          State      DTime   Interface  Router IP
172.80.39.50      1     Full/DR         37.581  bird-0-4-L fe80::250:56ff:fe30:309
bird> show bfd session
my_bfd1:
IP address                Interface  State      Since         Interval  Timeout
172.80.39.50              bird-0-4-L Up         11:49:02.041    1.000    3.000
fe80::250:56ff:fe30:309   bird-0-4-L Up         11:49:04.266    1.000    3.000
bird>

Added stuff in following files (not sure that would be enough for all cases but worked for my purpose): 
src/stx/common/trex_port.h
src/common/Network/Packet/TcpHeader.h    ### Even if UDP ports i put it here as DHCP (also UDP) was in same
src/44bsd/flow_table.cpp
src/stx/stl/trex_stl_dp_core.cpp
scripts/automation/trex_control_plane/interactive/trex/common/trex_client.py
scripts/automation/trex_control_plane/interactive/trex/utils/parsing_opts.py

Below is what was added:

    // enum for m_service_mask
    enum service_filter {
        SERVICE_OFF  = 0,
        NO_TCP_UDP   = 1,
        BGP          = 1 << 1,
        DHCP         = 1 << 2, /* both for v4 and v6 */
        TRANSPORT    = 1 << 3, /* TCP & UDP with source (port& 0xff00 == 0xff00) generated by EMU */
        MDNS         = 1 << 4,  /* mDNS - multicast DNS - EMU */
        BFD          = 1 << 5  /* all BFD ports */
    };

src/common/Network/Packet/TcpHeader.h

#define BGP_PORT        179

#define DHCPv4_PORT     67
#define DHCPv6_PORT     546
#define MDNS_PORT       5353
#define BFDc_PORT       3784
#define BFDe_PORT       3785
#define mBFDc_PORT      4784



vi ./src/44bsd/flow_table.cpp
void CFlowTable::check_service_filter(CSimplePacketParser & parser, tcp_rx_pkt_action_t & action) {
    if ( (get_astf_object()->get_state() == AstfProfileState::STATE_IDLE) && (m_service_status == SERVICE_ON) ) {
        action = tREDIRECT_RX_CORE;
        return;
    }
    if ( m_service_status == SERVICE_ON ){
                action = tREDIRECT_RX_CORE;
                return;
    }

    if (m_service_filtered_mask & TrexPort::BGP) {
        if ( parser.m_protocol == IPPROTO_TCP ) {
            TCPHeader *l4_header = (TCPHeader *)parser.m_l4;
            uint16_t src_port = l4_header->getSourcePort();
            uint16_t dst_port = l4_header->getDestPort();
            if ( src_port == BGP_PORT || dst_port == BGP_PORT ) {
                action = tREDIRECT_RX_CORE;
                return;
            }
        }
    }

    if (m_service_filtered_mask & TrexPort::DHCP) {
        if ( parser.m_protocol == IPPROTO_UDP ) {
            UDPHeader *l4_header = (UDPHeader *)parser.m_l4;
            uint16_t src_port = l4_header->getSourcePort();
            uint16_t dst_port = l4_header->getDestPort();
            if ( (( src_port == DHCPv4_PORT || dst_port == DHCPv4_PORT ))  ||
                 (( src_port == DHCPv6_PORT || dst_port == DHCPv6_PORT ))) {
                action = tREDIRECT_RX_CORE;
                return;
            }
        }
    }
    if (m_service_filtered_mask & TrexPort::BFD) {
        if ( parser.m_protocol == IPPROTO_UDP ) {
            UDPHeader *l4_header = (UDPHeader *)parser.m_l4;
            uint16_t src_port = l4_header->getSourcePort();
            uint16_t dst_port = l4_header->getDestPort();
            if ( (( src_port == BFDc_PORT || dst_port == BFDc_PORT ))  ||
                 (( src_port == BFDe_PORT || dst_port == BFDe_PORT ))  ||
                 (( src_port == mBFDc_PORT || dst_port == mBFDc_PORT ))) {
                action = tREDIRECT_RX_CORE;
                return;
            }
        }
    }


    if ( (m_service_filtered_mask & TrexPort::TRANSPORT) &&
            ((parser.m_protocol == IPPROTO_UDP) || (parser.m_protocol == IPPROTO_TCP)) ) {
        UDPHeader *l4_header = (UDPHeader *)parser.m_l4;
        uint16_t src_port = l4_header->getSourcePort();
        uint16_t dst_port = l4_header->getDestPort();
        if ( (dst_port & 0xff00) == 0xff00 || (src_port & 0xff00) == 0xff00 ) {
            action = tREDIRECT_RX_CORE;
            return;
        }
    }



vi ./src/stx/stl/trex_stl_dp_core.cpp

/* return true if packet passed through service filter */
COLD_FUNC bool TrexStatelessDpCore::check_service_filter(bool &drop) {

    uint8_t proto = m_parser->get_protocol();

    // BGP check
    if ( (m_service_mask & TrexPort::BGP) && (proto == IPPROTO_TCP) ) {

        TCPHeader *l4_header = (TCPHeader *)m_parser->get_l4();
        uint16_t src_port = l4_header->getSourcePort();
        uint16_t dst_port = l4_header->getDestPort();

        if ( src_port == BGP_PORT || dst_port == BGP_PORT ) {
            drop = false;
            return true;
        }
    }

    if ( (m_service_mask & TrexPort::DHCP) && (proto == IPPROTO_UDP) ) {
        UDPHeader *l4_header = (UDPHeader *)m_parser->get_l4();
        uint16_t src_port = l4_header->getSourcePort();
        uint16_t dst_port = l4_header->getDestPort();

        if ( (( src_port == DHCPv4_PORT || dst_port == DHCPv4_PORT )) ||
            (( src_port == DHCPv6_PORT || dst_port == DHCPv6_PORT ))) {
            drop = false;
            return true;
        }
    }

    if ( (m_service_mask & TrexPort::BFD) && (proto == IPPROTO_UDP) ) {
        UDPHeader *l4_header = (UDPHeader *)m_parser->get_l4();
        uint16_t src_port = l4_header->getSourcePort();
        uint16_t dst_port = l4_header->getDestPort();

        if ( (( src_port == BFDc_PORT || dst_port == BFDc_PORT )) ||
            (( src_port == BFDe_PORT || dst_port == BFDe_PORT )) ||
            (( src_port == mBFDc_PORT || dst_port == mBFDc_PORT ))) {
            drop = false;
            return true;
        }
    }


    if ( (m_service_mask & TrexPort::TRANSPORT) && ((proto == IPPROTO_UDP)
                                                     || (proto == IPPROTO_TCP)) ) {
        UDPHeader *l4_header = (UDPHeader *)m_parser->get_l4();
        uint16_t src_port = l4_header->getSourcePort();
        uint16_t dst_port = l4_header->getDestPort();

        if ( (dst_port&0xff00) == 0xff00 || (src_port&0xff00) == 0xff00 ) {
            drop = false;
            return true;
        }
    }

vi scripts/automation/trex_control_plane/interactive/trex/common/trex_client.py

## Filtered Service Mode Mask ##
## IMPORTANT - UPDATE ALSO in set_service_mode() docstring! ##
NO_MASK             = 0
NO_TCP_UDP_MASK     = 1
BGP_MASK            = 2
DHCP_MASK           = 4
TRANSPORT_MASK      = 8
MDNS_MASK           = 16
BFD_MASK            = 32
ALL_MASK            = 255  # all bits are on


.
.
.

    def set_service_mode_base (self, ports = None, enabled = True, filtered = False, mask = None):
        """
            Set service mode for port(s)
            In service mode ports will respond to ARP, PING and etc. "enable" and "filtered" are mutual exclusive,
            choose 1 of them or none

            :parameters:
                ports: list
                    For which ports to configure service mode on/off
                enabled: bool
                    True for activating service mode, False for disabling. Mutual exclusive with "filtered"
                filtered: bool
                    True for activating service filtered mode, False for disabling. Mutual exclusive with "enabled"
                mask: int
                    Mask to apply on each port in ports while filtered mode is on. Only packets that are correspond
                    to the port mask will be transferred.
                    Masks flags:
                    NO_MASK         = 0
                    NO_TCP_UDP_MASK = 1
                    BGP_MASK        = 2
                    DHCP_MASK       = 4
                    TRANSPORT       = 8
                    MDNS            = 16
                    BFD_MASK        = 32
                    ALL_MASK        = 255



.
.
.

    def _get_service_params(self, opts):
        """
        Common function, creates 3 arguments for set_service_mode

            :parameters:
                opts: argparse
                    The result of: parser.parse_args(line.split()).

            :return:
                3 arguments: enable, filtered & mask to use in set_service_mode
        """

        filtered = opts.allow_no_tcp_udp or opts.allow_bgp or opts.allow_all or opts.allow_emu or opts.allow_dhcp or opts.allow_transport or opts.allow_bfd

        mask = 0
        if filtered:
            if opts.allow_dhcp:
                mask |= DHCP_MASK
            if opts.allow_mdns:
                mask |= MDNS_MASK
            if opts.allow_emu:
                mask |= ( DHCP_MASK | MDNS_MASK | NO_TCP_UDP_MASK | TRANSPORT_MASK )
            if opts.allow_all:
                mask = ALL_MASK
            if opts.allow_bgp:
                mask |= BGP_MASK
            if opts.allow_no_tcp_udp:
                mask |= NO_TCP_UDP_MASK
            if opts.allow_transport:
                mask |= TRANSPORT_MASK
            if opts.allow_bfd:
                mask |= BFD_MASK


        else:
            mask = None
        enabled = False if filtered else opts.enabled

        return enabled, filtered, mask





scripts/automation/trex_control_plane/interactive/trex/utils/parsing_opts.py


    SERVICE_BGP_FILTERED = ArgumentPack(
        ['--bgp'],
        {'action': 'store_true',
         'default': False,
         'dest': 'allow_bgp',
         'help': 'filter mode with bgp packets forward to rx'})

    SERVICE_BFD_FILTERED = ArgumentPack(
        ['--bfd'],
        {'action': 'store_true',
         'default': False,
         'dest': 'allow_bfd',
         'help': 'filter mode with bfd packets forward to rx'})
 
.
.
.  
 
    SERVICE_GROUP = ArgumentGroup(
        NON_MUTEX,
        [
            SERVICE_BGP_FILTERED,
            SERVICE_BFD_FILTERED,
            SERVICE_DHCP_FILTERED,
            SERVICE_MDNS_FILTERED,
            SERVICE_EMU_FILTERED,
            SERVICE_TRAN_FILTERED,
            SERVICE_NO_TCP_UDP_FILTERED,
            SERVICE_ALL_FILTERED,
            SERVICE_OFF
        ],{})

Thanks//Håkan

hanoh haim

unread,
Jul 7, 2024, 6:27:47 AMJul 7
to Haklat haklat, TRex Traffic Generator
Hi Haklat,
I would be a good idea to create a PR if you have time

Thanks
Hanoh

Reply all
Reply to author
Forward
0 new messages