Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
I
iproute2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
iproute2
Commits
00fa8480
Commit
00fa8480
authored
Dec 08, 2004
by
net[shemminger]!shemminger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Import patch mirred.patch
(Logical change 1.111)
parent
d74b15e1
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
422 additions
and
1 deletion
+422
-1
ChangeLog
ChangeLog
+4
-0
configure
configure
+8
-1
doc/actions/mirred-usage
doc/actions/mirred-usage
+71
-0
include/linux/tc_act/tc_mirred.h
include/linux/tc_act/tc_mirred.h
+28
-0
tc/Makefile
tc/Makefile
+1
-0
tc/m_mirred.c
tc/m_mirred.c
+310
-0
No files found.
ChangeLog
View file @
00fa8480
2004-12-08 Jamal Hadi Salim <hadi@znyx.com>
* Add mirror and redirect actions
2004-10-20 Stephen Hemminger <shemminger@osdl.org>
* Don't include <asm/byteorder.h> since then we get dependant on
...
...
configure
View file @
00fa8480
...
...
@@ -26,12 +26,19 @@ else
fi
rm
-f
/tmp/atmtest.c /tmp/atmtest
# hack for now
# hack
s
for now
echo
"TC actions"
if
[
-e
"tc/m_gact.c"
]
then
echo
" GACT found"
echo
"TC_CONFIG_ACTION_GACT=y"
>>
Config
echo
"TC_CONFIG_ACTION_PROB=y"
>>
Config
fi
if
[
-e
"tc/m_mirred.c"
]
then
echo
" MIRRED found"
echo
"TC_CONFIG_ACTION_MIRRED=y"
>>
Config
fi
doc/actions/mirred-usage
View file @
00fa8480
Very funky action. I do plan to add to a few more things to it
This is the basic stuff. Idea borrowed from the way ethernet switches
mirror and redirect packets.
Usage:
mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>
where:
DIRECTION := <ingress | egress>
ACTION := <mirror | redirect>
INDEX is the specific policy instance id
DEVICENAME is the devicename
Mirroring essentially takes a copy of the packet whereas redirecting
steals the packet and redirects to specified destination.
Some examples:
Host A is hooked up to us on eth0
tc qdisc add dev lo ingress
# redirect all packets arriving on ingress of lo to eth0
tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
match u32 0 0 flowid 1:2 action mirred egress redirect dev eth0
On host A start a tcpdump on interface connecting to us.
on our host ping -c 2 127.0.0.1
Ping would fail sinc all packets are heading out eth0
tcpudmp on host A would show them
if you substitute the redirect with mirror above as in:
tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
match u32 0 0 flowid 1:2 action mirred egress mirror dev eth0
Then you should see the packets on both host A and the local
stack (i.e ping would work).
Even more funky example:
#
#allow 1 out 10 packets to randomly make it to the
# host A (Randomness uses the netrand generator)
#
tc filter add dev lo parent ffff: protocol ip prio 10 u32 \
match u32 0 0 flowid 1:2 \
action drop random determ ok 10\
action mirred egress mirror dev eth0
------
Example 2:
# for packets coming from 10.0.0.9:
#Redirect packets on egress (to ISP A) if you exceed a certain rate
# to eth1 (to ISP B) if you exceed a certain rate
#
tc qdisc add dev eth0 handle 1:0 root prio
tc filter add dev eth0 parent 1:0 protocol ip prio 6 u32 \
match ip src 10.0.0.9/32 flowid 1:16 \
action police rate 100kbit burst 90k ok \
action mirred egress mirror dev eth1
---
A more interesting example is when you mirror flows to a dummy device
so you could tcpdump them (dummy by defaults drops all devices it sees).
This is a very useful debug feature.
include/linux/tc_act/tc_mirred.h
View file @
00fa8480
#ifndef __LINUX_TC_MIR_H
#define __LINUX_TC_MIR_H
#include <linux/pkt_cls.h>
#define TCA_ACT_MIRRED 8
#define TCA_EGRESS_REDIR 1
/* packet redirect to EGRESS*/
#define TCA_EGRESS_MIRROR 2
/* mirror packet to EGRESS */
#define TCA_INGRESS_REDIR 3
/* packet redirect to INGRESS*/
#define TCA_INGRESS_MIRROR 4
/* mirror packet to INGRESS */
struct
tc_mirred
{
tc_gen
;
int
eaction
;
/* one of IN/EGRESS_MIRROR/REDIR */
__u32
ifindex
;
/* ifindex of egress port */
};
enum
{
TCA_MIRRED_UNSPEC
,
TCA_MIRRED_TM
,
TCA_MIRRED_PARMS
,
__TCA_MIRRED_MAX
};
#define TCA_MIRRED_MAX (__TCA_MIRRED_MAX - 1)
#endif
tc/Makefile
View file @
00fa8480
...
...
@@ -21,6 +21,7 @@ TCMODULES += q_ingress.o
TCMODULES
+=
q_hfsc.o
TCMODULES
+=
q_htb.o
TCMODULES
+=
m_gact.o
TCMODULES
+=
m_mirred.o
TCOBJ
+=
$(TCMODULES)
...
...
tc/m_mirred.c
View file @
00fa8480
/*
* m_egress.c ingress/egress packet mirror/redir actions module
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: J Hadi Salim (hadi@cyberus.ca)
*
* TODO: Add Ingress support
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "utils.h"
#include "tc_util.h"
#include <linux/tc_act/tc_mirred.h>
int
mirred_d
=
1
;
static
void
explain
(
void
)
{
fprintf
(
stderr
,
"Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>
\n
"
);
fprintf
(
stderr
,
"where:
\n
"
);
fprintf
(
stderr
,
"DIRECTION := <ingress | egress>
\n
"
);
fprintf
(
stderr
,
"aCTION := <mirror | redirect>
\n
"
);
fprintf
(
stderr
,
" : INDEX is the specific policy instance id
\n
"
);
fprintf
(
stderr
,
" : DEVICENAME is the devicename
\n
"
);
}
#define usage() return(-1)
char
*
mirred_n2a
(
int
action
)
{
switch
(
action
)
{
case
TCA_EGRESS_REDIR
:
return
"Egress Redirect"
;
case
TCA_INGRESS_REDIR
:
return
"Ingress Redirect"
;
case
TCA_EGRESS_MIRROR
:
return
"Egress Mirror"
;
case
TCA_INGRESS_MIRROR
:
return
"Ingress Mirror"
;
default:
return
"unknown"
;
}
}
int
parse_egress
(
struct
action_util
*
a
,
int
*
argc_p
,
char
***
argv_p
,
int
tca_id
,
struct
nlmsghdr
*
n
)
{
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
int
ok
=
0
,
iok
=
0
,
mirror
=
0
,
redir
=
0
;
struct
tc_mirred
p
;
struct
rtattr
*
tail
;
char
d
[
16
];
struct
rtnl_handle
rth
;
memset
(
d
,
0
,
sizeof
(
d
)
-
1
);
memset
(
&
p
,
0
,
sizeof
(
struct
tc_mirred
));
while
(
argc
>
0
)
{
if
(
matches
(
*
argv
,
"action"
)
==
0
)
{
break
;
}
else
if
(
matches
(
*
argv
,
"egress"
)
==
0
)
{
NEXT_ARG
();
ok
++
;
continue
;
}
else
{
if
(
matches
(
*
argv
,
"index"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
p
.
index
,
*
argv
,
10
))
{
fprintf
(
stderr
,
"Illegal
\"
index
\"\n
"
);
return
-
1
;
}
iok
++
;
if
(
!
ok
)
{
argc
--
;
argv
++
;
break
;
}
}
else
if
(
!
ok
)
{
fprintf
(
stderr
,
"was expecting egress (%s)
\n
"
,
*
argv
);
break
;
}
else
if
(
!
mirror
&&
matches
(
*
argv
,
"mirror"
)
==
0
)
{
mirror
=
1
;
if
(
redir
)
{
fprintf
(
stderr
,
"Cant have both mirror and redir
\n
"
);
return
-
1
;
}
p
.
eaction
=
TCA_EGRESS_MIRROR
;
p
.
action
=
TC_ACT_PIPE
;
ok
++
;
}
else
if
(
!
redir
&&
matches
(
*
argv
,
"redirect"
)
==
0
)
{
redir
=
1
;
if
(
mirror
)
{
fprintf
(
stderr
,
"Cant have both mirror and redir
\n
"
);
return
-
1
;
}
p
.
eaction
=
TCA_EGRESS_REDIR
;
p
.
action
=
TC_ACT_STOLEN
;
ok
++
;
}
else
if
((
redir
||
mirror
)
&&
matches
(
*
argv
,
"dev"
)
==
0
)
{
NEXT_ARG
();
if
(
strlen
(
d
))
duparg
(
"dev"
,
*
argv
);
strncpy
(
d
,
*
argv
,
sizeof
(
d
)
-
1
);
argc
--
;
argv
++
;
break
;
}
}
NEXT_ARG
();
}
if
(
!
ok
&&
!
iok
)
{
explain
();
return
-
1
;
}
if
(
d
[
0
])
{
int
idx
;
if
(
rtnl_open
(
&
rth
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Cannot open rtnetlink
\n
"
);
exit
(
1
);
}
ll_init_map
(
&
rth
);
if
((
idx
=
ll_name_to_index
(
d
))
==
0
)
{
fprintf
(
stderr
,
"Cannot find device
\"
%s
\"\n
"
,
d
);
rtnl_close
(
&
rth
);
return
-
1
;
}
p
.
ifindex
=
idx
;
rtnl_close
(
&
rth
);
}
if
(
argc
&&
p
.
eaction
==
TCA_EGRESS_MIRROR
)
{
if
(
matches
(
*
argv
,
"reclassify"
)
==
0
)
{
p
.
action
=
TC_POLICE_RECLASSIFY
;
NEXT_ARG
();
}
else
if
(
matches
(
*
argv
,
"pipe"
)
==
0
)
{
p
.
action
=
TC_POLICE_PIPE
;
NEXT_ARG
();
}
else
if
(
matches
(
*
argv
,
"drop"
)
==
0
||
matches
(
*
argv
,
"shot"
)
==
0
)
{
p
.
action
=
TC_POLICE_SHOT
;
NEXT_ARG
();
}
else
if
(
matches
(
*
argv
,
"continue"
)
==
0
)
{
p
.
action
=
TC_POLICE_UNSPEC
;
NEXT_ARG
();
}
else
if
(
matches
(
*
argv
,
"pass"
)
==
0
)
{
p
.
action
=
TC_POLICE_OK
;
NEXT_ARG
();
}
}
if
(
argc
)
{
if
(
iok
&&
matches
(
*
argv
,
"index"
)
==
0
)
{
fprintf
(
stderr
,
"mirred: Illegal double index
\n
"
);
return
-
1
;
}
else
{
if
(
matches
(
*
argv
,
"index"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
p
.
index
,
*
argv
,
10
))
{
fprintf
(
stderr
,
"mirred: Illegal
\"
index
\"\n
"
);
return
-
1
;
}
argc
--
;
argv
++
;
}
}
}
if
(
mirred_d
)
fprintf
(
stdout
,
"Action %d device %s ifindex %d
\n
"
,
p
.
action
,
d
,
p
.
ifindex
);
tail
=
(
struct
rtattr
*
)
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
));
addattr_l
(
n
,
MAX_MSG
,
tca_id
,
NULL
,
0
);
addattr_l
(
n
,
MAX_MSG
,
TCA_MIRRED_PARMS
,
&
p
,
sizeof
(
p
));
tail
->
rta_len
=
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
))
-
(
void
*
)
tail
;
*
argc_p
=
argc
;
*
argv_p
=
argv
;
return
0
;
}
int
parse_mirred
(
struct
action_util
*
a
,
int
*
argc_p
,
char
***
argv_p
,
int
tca_id
,
struct
nlmsghdr
*
n
)
{
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
if
(
argc
<
0
)
{
fprintf
(
stderr
,
"mirred bad arguement count %d
\n
"
,
argc
);
return
-
1
;
}
if
(
matches
(
*
argv
,
"mirred"
)
==
0
)
{
NEXT_ARG
();
}
else
{
fprintf
(
stderr
,
"mirred bad arguement %s
\n
"
,
*
argv
);
return
-
1
;
}
if
(
matches
(
*
argv
,
"egress"
)
==
0
||
matches
(
*
argv
,
"index"
)
==
0
)
{
int
ret
=
parse_egress
(
a
,
&
argc
,
&
argv
,
tca_id
,
n
);
if
(
ret
==
0
)
{
*
argc_p
=
argc
;
*
argv_p
=
argv
;
return
0
;
}
}
else
if
(
matches
(
*
argv
,
"ingress"
)
==
0
)
{
fprintf
(
stderr
,
"mirred ingress not supported at the moment
\n
"
);
}
else
{
fprintf
(
stderr
,
"mirred not supported %s
\n
"
,
*
argv
);
}
return
-
1
;
}
int
print_mirred
(
struct
action_util
*
au
,
FILE
*
f
,
struct
rtattr
*
arg
)
{
struct
tc_mirred
*
p
;
struct
rtattr
*
tb
[
TCA_MIRRED_MAX
+
1
];
struct
rtnl_handle
rth
;
const
char
*
dev
;
SPRINT_BUF
(
b1
);
if
(
arg
==
NULL
)
return
-
1
;
memset
(
tb
,
0
,
sizeof
(
tb
));
parse_rtattr
(
tb
,
TCA_MIRRED_MAX
,
RTA_DATA
(
arg
),
RTA_PAYLOAD
(
arg
));
if
(
tb
[
TCA_MIRRED_PARMS
]
==
NULL
)
{
fprintf
(
f
,
"[NULL mirred parameters]"
);
return
-
1
;
}
p
=
RTA_DATA
(
tb
[
TCA_MIRRED_PARMS
]);
if
(
rtnl_open
(
&
rth
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Cannot open rtnetlink
\n
"
);
return
-
1
;
}
ll_init_map
(
&
rth
);
if
((
dev
=
ll_index_to_name
(
p
->
ifindex
))
==
0
)
{
fprintf
(
stderr
,
"Cannot find device %d
\n
"
,
p
->
ifindex
);
rtnl_close
(
&
rth
);
return
-
1
;
}
fprintf
(
f
,
"mirred (%s to device %s) %s"
,
mirred_n2a
(
p
->
eaction
),
dev
,
action_n2a
(
p
->
action
,
b1
,
sizeof
(
b1
)));
fprintf
(
f
,
"
\n
"
);
fprintf
(
f
,
"
\t
index %d ref %d bind %d"
,
p
->
index
,
p
->
refcnt
,
p
->
bindcnt
);
if
(
show_stats
)
{
if
(
tb
[
TCA_MIRRED_TM
])
{
struct
tcf_t
*
tm
=
RTA_DATA
(
tb
[
TCA_MIRRED_TM
]);
print_tm
(
f
,
tm
);
}
}
fprintf
(
f
,
"
\n
"
);
rtnl_close
(
&
rth
);
return
0
;
}
struct
action_util
mirred_util
=
{
.
id
=
"mirred"
,
.
parse_aopt
=
parse_mirred
,
.
print_aopt
=
print_mirred
,
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment