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
68d5ba54
Commit
68d5ba54
authored
Aug 13, 2004
by
osdl.net!shemminger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
(Logical change 1.66)
parent
6c45560b
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
973 additions
and
0 deletions
+973
-0
include/linux/pkt_cls.h
include/linux/pkt_cls.h
+314
-0
tc/m_action.c
tc/m_action.c
+659
-0
No files found.
include/linux/pkt_cls.h
View file @
68d5ba54
#ifndef __LINUX_PKT_CLS_H
#define __LINUX_PKT_CLS_H
/* I think i could have done better macros ; for now this is stolen from
* some arch/mips code - jhs
*/
#define _TC_MAKE32(x) ((x))
#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n))
#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n))
#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n))
#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n))
/* verdict bit breakdown
*
bit 0: when set -> this packet has been munged already
bit 1: when set -> It is ok to munge this packet
bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded
assume loop
bit 6,7: Where this packet was last seen
0: Above the transmit example at the socket level
1: on the Ingress
2: on the Egress
bit 8: when set --> Request not to classify on ingress.
bits 9,10,11: redirect counter - redirect TTL. Loop avoidance
*
* */
#define TC_MUNGED _TC_MAKEMASK1(0)
#define SET_TC_MUNGED(v) ( TC_MUNGED | (v & ~TC_MUNGED))
#define CLR_TC_MUNGED(v) ( v & ~TC_MUNGED)
#define TC_OK2MUNGE _TC_MAKEMASK1(1)
#define SET_TC_OK2MUNGE(v) ( TC_OK2MUNGE | (v & ~TC_OK2MUNGE))
#define CLR_TC_OK2MUNGE(v) ( v & ~TC_OK2MUNGE)
#define S_TC_VERD _TC_MAKE32(2)
#define M_TC_VERD _TC_MAKEMASK(4,S_TC_VERD)
#define G_TC_VERD(x) _TC_GETVALUE(x,S_TC_VERD,M_TC_VERD)
#define V_TC_VERD(x) _TC_MAKEVALUE(x,S_TC_VERD)
#define SET_TC_VERD(v,n) ((V_TC_VERD(n)) | (v & ~M_TC_VERD))
#define S_TC_FROM _TC_MAKE32(6)
#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM)
#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM)
#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM)
#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM))
#define AT_STACK 0x0
#define AT_INGRESS 0x1
#define AT_EGRESS 0x2
#define TC_NCLS _TC_MAKEMASK1(8)
#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS))
#define CLR_TC_NCLS(v) ( v & ~TC_NCLS)
#define S_TC_RTTL _TC_MAKE32(9)
#define M_TC_RTTL _TC_MAKEMASK(3,S_TC_RTTL)
#define G_TC_RTTL(x) _TC_GETVALUE(x,S_TC_RTTL,M_TC_RTTL)
#define V_TC_RTTL(x) _TC_MAKEVALUE(x,S_TC_RTTL)
#define SET_TC_RTTL(v,n) ((V_TC_RTTL(n)) | (v & ~M_TC_RTTL))
#define S_TC_AT _TC_MAKE32(12)
#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT)
#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT)
#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT)
#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT))
/* Action attributes */
enum
{
TCA_ACT_UNSPEC
,
TCA_ACT_KIND
,
TCA_ACT_OPTIONS
,
TCA_ACT_INDEX
,
__TCA_ACT_MAX
};
#define TCA_ACT_MAX __TCA_ACT_MAX
#define TCA_OLD_COMPAT (TCA_ACT_MAX+1)
#define TCA_ACT_MAX_PRIO 32
#define TCA_ACT_BIND 1
#define TCA_ACT_NOBIND 0
#define TCA_ACT_UNBIND 1
#define TCA_ACT_NOUNBIND 0
#define TCA_ACT_REPLACE 1
#define TCA_ACT_NOREPLACE 0
#define MAX_REC_LOOP 4
#define MAX_RED_LOOP 4
#define TC_ACT_UNSPEC (-1)
#define TC_ACT_OK 0
#define TC_ACT_RECLASSIFY 1
#define TC_ACT_SHOT 2
#define TC_ACT_PIPE 3
#define TC_ACT_STOLEN 4
#define TC_ACT_QUEUED 5
#define TC_ACT_REPEAT 6
#define TC_ACT_JUMP 0x10000000
/* Action type identifiers*/
enum
{
TCA_ID_UNSPEC
=
0
,
TCA_ID_POLICE
=
1
,
/* other actions go here */
__TCA_ID_MAX
=
255
};
#define TCA_ID_MAX __TCA_ID_MAX
struct
tc_police
{
__u32
index
;
int
action
;
#define TC_POLICE_UNSPEC TC_ACT_UNSPEC
#define TC_POLICE_OK TC_ACT_OK
#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY
#define TC_POLICE_SHOT TC_ACT_SHOT
#define TC_POLICE_PIPE TC_ACT_PIPE
__u32
limit
;
__u32
burst
;
__u32
mtu
;
struct
tc_ratespec
rate
;
struct
tc_ratespec
peakrate
;
int
refcnt
;
int
bindcnt
;
__u32
capab
;
};
struct
tcf_t
{
__u32
install
;
__u32
lastuse
;
__u32
expires
;
};
struct
tc_cnt
{
int
refcnt
;
int
bindcnt
;
};
#define tc_gen \
__u32 index; \
__u32 capab; \
int action; \
int refcnt; \
int bindcnt
enum
{
TCA_POLICE_UNSPEC
,
TCA_POLICE_TBF
,
TCA_POLICE_RATE
,
TCA_POLICE_PEAKRATE
,
TCA_POLICE_AVRATE
,
TCA_POLICE_RESULT
,
__TCA_POLICE_MAX
#define TCA_POLICE_RESULT TCA_POLICE_RESULT
};
#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1)
/* U32 filters */
#define TC_U32_HTID(h) ((h)&0xFFF00000)
#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20)
#define TC_U32_HASH(h) (((h)>>12)&0xFF)
#define TC_U32_NODE(h) ((h)&0xFFF)
#define TC_U32_KEY(h) ((h)&0xFFFFF)
#define TC_U32_UNSPEC 0
#define TC_U32_ROOT (0xFFF00000)
enum
{
TCA_U32_UNSPEC
,
TCA_U32_CLASSID
,
TCA_U32_HASH
,
TCA_U32_LINK
,
TCA_U32_DIVISOR
,
TCA_U32_SEL
,
TCA_U32_POLICE
,
TCA_U32_ACT
,
TCA_U32_INDEV
,
TCA_U32_PCNT
,
__TCA_U32_MAX
};
#define TCA_U32_MAX (__TCA_U32_MAX - 1)
struct
tc_u32_key
{
__u32
mask
;
__u32
val
;
int
off
;
int
offmask
;
};
struct
tc_u32_sel
{
unsigned
char
flags
;
unsigned
char
offshift
;
unsigned
char
nkeys
;
__u16
offmask
;
__u16
off
;
short
offoff
;
short
hoff
;
__u32
hmask
;
struct
tc_u32_key
keys
[
0
];
};
struct
tc_u32_pcnt
{
__u64
rcnt
;
__u64
rhit
;
__u64
kcnts
[
0
];
};
/* Flags */
#define TC_U32_TERMINAL 1
#define TC_U32_OFFSET 2
#define TC_U32_VAROFFSET 4
#define TC_U32_EAT 8
#define TC_U32_MAXDEPTH 8
/* RSVP filter */
enum
{
TCA_RSVP_UNSPEC
,
TCA_RSVP_CLASSID
,
TCA_RSVP_DST
,
TCA_RSVP_SRC
,
TCA_RSVP_PINFO
,
TCA_RSVP_POLICE
,
__TCA_RSVP_MAX
};
#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 )
struct
tc_rsvp_gpi
{
__u32
key
;
__u32
mask
;
int
offset
;
};
struct
tc_rsvp_pinfo
{
struct
tc_rsvp_gpi
dpi
;
struct
tc_rsvp_gpi
spi
;
__u8
protocol
;
__u8
tunnelid
;
__u8
tunnelhdr
;
};
/* ROUTE filter */
enum
{
TCA_ROUTE4_UNSPEC
,
TCA_ROUTE4_CLASSID
,
TCA_ROUTE4_TO
,
TCA_ROUTE4_FROM
,
TCA_ROUTE4_IIF
,
TCA_ROUTE4_POLICE
,
__TCA_ROUTE4_MAX
};
#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1)
/* FW filter */
enum
{
TCA_FW_UNSPEC
,
TCA_FW_CLASSID
,
TCA_FW_POLICE
,
TCA_FW_INDEV
,
/* used by CONFIG_NET_CLS_IND */
TCA_FW_ACT
,
/* used by CONFIG_NET_CLS_ACT */
__TCA_FW_MAX
};
#define TCA_FW_MAX (__TCA_FW_MAX - 1)
/* TC index filter */
enum
{
TCA_TCINDEX_UNSPEC
,
TCA_TCINDEX_HASH
,
TCA_TCINDEX_MASK
,
TCA_TCINDEX_SHIFT
,
TCA_TCINDEX_FALL_THROUGH
,
TCA_TCINDEX_CLASSID
,
TCA_TCINDEX_POLICE
,
__TCA_TCINDEX_MAX
};
#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1)
#endif
tc/m_action.c
View file @
68d5ba54
/*
* m_action.c Action Management
*
* 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:
* - parse to be passed a filedescriptor for logging purposes
*
*/
#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 <dlfcn.h>
#include "utils.h"
#include "tc_util.h"
void
*
aBODY
;
static
struct
action_util
*
action_list
;
#ifdef CONFIG_GACT
int
gact_ld
=
0
;
//fuckin backward compatibility
#endif
int
batch_c
=
0
;
int
tab_flush
=
0
;
void
act_usage
(
void
)
{
fprintf
(
stderr
,
"action usage improper
\n
"
);
}
static
int
print_noaopt
(
struct
action_util
*
au
,
FILE
*
f
,
struct
rtattr
*
opt
)
{
if
(
opt
&&
RTA_PAYLOAD
(
opt
))
fprintf
(
f
,
"[Unknown action, optlen=%u] "
,
RTA_PAYLOAD
(
opt
));
return
0
;
}
static
int
parse_noaopt
(
struct
action_util
*
au
,
int
*
argc_p
,
char
***
argv_p
,
int
code
,
struct
nlmsghdr
*
n
)
{
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
if
(
argc
)
{
fprintf
(
stderr
,
"Unknown action
\"
%s
\"
, hence option
\"
%s
\"
is unparsable
\n
"
,
au
->
id
,
*
argv
);
}
else
{
fprintf
(
stderr
,
"Unknown action
\"
%s
\"\n
"
,
au
->
id
);
}
return
-
1
;
}
struct
action_util
*
get_action_kind
(
char
*
str
)
{
void
*
dlh
;
char
buf
[
256
];
struct
action_util
*
a
;
#ifdef CONFIG_GACT
int
looked4gact
=
0
;
restart_s:
#endif
for
(
a
=
action_list
;
a
;
a
=
a
->
next
)
{
if
(
strcmp
(
a
->
id
,
str
)
==
0
)
return
a
;
}
snprintf
(
buf
,
sizeof
(
buf
),
"m_%s.so"
,
str
);
dlh
=
dlopen
(
buf
,
RTLD_LAZY
);
if
(
dlh
==
NULL
)
{
dlh
=
aBODY
;
if
(
dlh
==
NULL
)
{
dlh
=
aBODY
=
dlopen
(
NULL
,
RTLD_LAZY
);
if
(
dlh
==
NULL
)
goto
noexist
;
}
}
snprintf
(
buf
,
sizeof
(
buf
),
"%s_util"
,
str
);
a
=
dlsym
(
dlh
,
buf
);
if
(
a
==
NULL
)
goto
noexist
;
reg:
a
->
next
=
action_list
;
action_list
=
a
;
return
a
;
noexist:
#ifdef CONFIG_GACT
if
(
!
looked4gact
)
{
looked4gact
=
1
;
strcpy
(
str
,
"gact"
);
goto
restart_s
;
}
#endif
a
=
malloc
(
sizeof
(
*
a
));
if
(
a
)
{
memset
(
a
,
0
,
sizeof
(
*
a
));
strncpy
(
a
->
id
,
"noact"
,
15
);
a
->
parse_aopt
=
parse_noaopt
;
a
->
print_aopt
=
print_noaopt
;
goto
reg
;
}
return
a
;
}
int
new_cmd
(
char
**
argv
)
{
if
((
matches
(
*
argv
,
"change"
)
==
0
)
||
(
matches
(
*
argv
,
"replace"
)
==
0
)
||
(
matches
(
*
argv
,
"delete"
)
==
0
)
||
(
matches
(
*
argv
,
"add"
)
==
0
))
return
1
;
return
0
;
}
int
parse_action
(
int
*
argc_p
,
char
***
argv_p
,
int
tca_id
,
struct
nlmsghdr
*
n
)
{
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
struct
rtattr
*
tail
,
*
tail2
;
char
k
[
16
];
int
ok
=
0
;
int
eap
=
0
;
/* expect action parameters */
int
ret
=
0
;
int
prio
=
0
;
if
(
argc
<=
0
)
return
-
1
;
tail
=
tail2
=
(
struct
rtattr
*
)
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
));
addattr_l
(
n
,
MAX_MSG
,
tca_id
,
NULL
,
0
);
while
(
argc
>
0
)
{
memset
(
k
,
0
,
sizeof
(
k
));
if
(
strcmp
(
*
argv
,
"action"
)
==
0
)
{
argc
--
;
argv
++
;
eap
=
1
;
#ifdef CONFIG_GACT
if
(
!
gact_ld
)
{
get_action_kind
(
"gact"
);
}
#endif
continue
;
}
else
if
(
strcmp
(
*
argv
,
"help"
)
==
0
)
{
return
-
1
;
}
else
if
(
new_cmd
(
argv
))
{
goto
done0
;
}
else
{
struct
action_util
*
a
=
NULL
;
strncpy
(
k
,
*
argv
,
sizeof
(
k
)
-
1
);
eap
=
0
;
if
(
argc
>
0
)
{
a
=
get_action_kind
(
k
);
}
else
{
done0:
if
(
ok
)
break
;
else
goto
done
;
}
if
(
NULL
==
a
)
{
goto
bad_val
;
}
tail
=
(
struct
rtattr
*
)
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
));
addattr_l
(
n
,
MAX_MSG
,
++
prio
,
NULL
,
0
);
addattr_l
(
n
,
MAX_MSG
,
TCA_ACT_KIND
,
k
,
strlen
(
k
)
+
1
);
ret
=
a
->
parse_aopt
(
a
,
&
argc
,
&
argv
,
TCA_ACT_OPTIONS
,
n
);
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"bad action parsing
\n
"
);
goto
bad_val
;
}
tail
->
rta_len
=
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
))
-
(
void
*
)
tail
;
ok
++
;
}
}
if
(
eap
>
0
)
{
fprintf
(
stderr
,
"bad action empty %d
\n
"
,
eap
);
goto
bad_val
;
}
tail2
->
rta_len
=
(((
void
*
)
n
)
+
NLMSG_ALIGN
(
n
->
nlmsg_len
))
-
(
void
*
)
tail2
;
done:
*
argc_p
=
argc
;
*
argv_p
=
argv
;
return
0
;
bad_val:
/* no need to undo things, returning from here should
* cause enough pain */
fprintf
(
stderr
,
"parse_action: bad value (%d:%s)!
\n
"
,
argc
,
*
argv
);
return
-
1
;
}
int
tc_print_one_action
(
FILE
*
f
,
struct
rtattr
*
arg
)
{
struct
rtattr
*
tb
[
TCA_ACT_MAX
+
1
];
int
err
=
0
;
struct
action_util
*
a
=
NULL
;
if
(
arg
==
NULL
)
return
-
1
;
memset
(
tb
,
0
,
sizeof
(
tb
));
parse_rtattr
(
tb
,
TCA_ACT_MAX
,
RTA_DATA
(
arg
),
RTA_PAYLOAD
(
arg
));
if
(
tb
[
TCA_ACT_KIND
]
==
NULL
)
{
fprintf
(
stderr
,
"NULL Action!
\n
"
);
return
-
1
;
}
a
=
get_action_kind
(
RTA_DATA
(
tb
[
TCA_ACT_KIND
]));
if
(
NULL
==
a
)
return
err
;
if
(
tab_flush
)
{
fprintf
(
f
,
" %s
\n
"
,
a
->
id
);
tab_flush
=
0
;
return
0
;
}
err
=
a
->
print_aopt
(
a
,
f
,
tb
[
TCA_ACT_OPTIONS
]);
if
(
0
>
err
)
return
err
;
if
(
show_stats
)
{
if
(
tb
[
TCA_STATS
])
{
#ifndef STOOPID_8BYTE
if
(
RTA_PAYLOAD
(
tb
[
TCA_STATS
])
<
sizeof
(
struct
tc_stats
))
fprintf
(
f
,
"statistics truncated"
);
else
{
#endif
struct
tc_stats
st
;
memcpy
(
&
st
,
RTA_DATA
(
tb
[
TCA_STATS
]),
sizeof
(
st
));
fprintf
(
f
,
"
\t
"
);
print_tcstats
(
f
,
&
st
);
fprintf
(
f
,
"
\n
"
);
#ifndef STOOPID_8BYTE
}
#endif
}
}
return
0
;
}
int
tc_print_action
(
FILE
*
f
,
struct
rtattr
*
arg
)
{
int
i
;
struct
rtattr
*
tb
[
TCA_ACT_MAX_PRIO
+
1
];
if
(
arg
==
NULL
)
return
0
;
memset
(
tb
,
0
,
sizeof
(
tb
));
parse_rtattr
(
tb
,
TCA_ACT_MAX_PRIO
,
RTA_DATA
(
arg
),
RTA_PAYLOAD
(
arg
));
if
(
tab_flush
&&
NULL
!=
tb
[
0
]
&&
NULL
==
tb
[
1
])
{
int
ret
=
tc_print_one_action
(
f
,
tb
[
0
]);
return
ret
;
}
for
(
i
=
0
;
i
<
TCA_ACT_MAX_PRIO
;
i
++
)
{
if
(
tb
[
i
])
{
fprintf
(
f
,
"
\n\t
action order %d: "
,
i
+
batch_c
);
if
(
0
>
tc_print_one_action
(
f
,
tb
[
i
]))
{
fprintf
(
f
,
"Error printing action
\n
"
);
}
}
}
batch_c
+=
TCA_ACT_MAX_PRIO
;
return
0
;
}
int
do_print_action
(
struct
sockaddr_nl
*
who
,
struct
nlmsghdr
*
n
,
void
*
arg
)
{
FILE
*
fp
=
(
FILE
*
)
arg
;
struct
tcamsg
*
t
=
NLMSG_DATA
(
n
);
int
len
=
n
->
nlmsg_len
;
struct
rtattr
*
tb
[
TCAA_MAX
+
1
];
len
-=
NLMSG_LENGTH
(
sizeof
(
*
t
));
if
(
len
<
0
)
{
fprintf
(
stderr
,
"Wrong len %d
\n
"
,
len
);
return
-
1
;
}
memset
(
tb
,
0
,
sizeof
(
tb
));
parse_rtattr
(
tb
,
TCAA_MAX
,
TA_RTA
(
t
),
len
);
if
(
NULL
==
tb
[
TCA_ACT_TAB
])
{
if
(
n
->
nlmsg_type
!=
RTM_GETACTION
)
fprintf
(
stderr
,
"do_print_action: NULL kind
\n
"
);
return
-
1
;
}
if
(
n
->
nlmsg_type
==
RTM_DELACTION
)
{
if
(
n
->
nlmsg_flags
&
NLM_F_ROOT
)
{
fprintf
(
fp
,
"Flushed table "
);
tab_flush
=
1
;
}
else
{
fprintf
(
fp
,
"deleted action "
);
}
}
if
(
n
->
nlmsg_type
==
RTM_NEWACTION
)
fprintf
(
fp
,
"Added action "
);
tc_print_action
(
fp
,
tb
[
TCA_ACT_TAB
]);
return
0
;
}
int
tc_action_gd
(
int
cmd
,
unsigned
flags
,
int
*
argc_p
,
char
***
argv_p
)
{
char
k
[
16
];
struct
action_util
*
a
=
NULL
;
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
int
prio
=
0
;
int
ret
=
0
;
__u32
i
;
struct
rtnl_handle
rth
;
struct
sockaddr_nl
nladdr
;
struct
rtattr
*
tail
;
struct
rtattr
*
tail2
;
struct
nlmsghdr
*
ans
=
NULL
;
struct
{
struct
nlmsghdr
n
;
struct
tcamsg
t
;
char
buf
[
MAX_MSG
];
}
req
;
req
.
t
.
tca_family
=
AF_UNSPEC
;
memset
(
&
req
,
0
,
sizeof
(
req
));
memset
(
&
nladdr
,
0
,
sizeof
(
nladdr
));
nladdr
.
nl_family
=
AF_NETLINK
;
req
.
n
.
nlmsg_len
=
NLMSG_LENGTH
(
sizeof
(
struct
tcamsg
));
req
.
n
.
nlmsg_flags
=
NLM_F_REQUEST
|
flags
;
req
.
n
.
nlmsg_type
=
cmd
;
argc
-=
1
;
argv
+=
1
;
tail
=
(
struct
rtattr
*
)(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
));
addattr_l
(
&
req
.
n
,
MAX_MSG
,
TCA_ACT_TAB
,
NULL
,
0
);
while
(
argc
>
0
)
{
if
(
strcmp
(
*
argv
,
"action"
)
==
0
)
{
argc
--
;
argv
++
;
continue
;
}
else
if
(
strcmp
(
*
argv
,
"help"
)
==
0
)
{
return
-
1
;
}
strncpy
(
k
,
*
argv
,
sizeof
(
k
)
-
1
);
a
=
get_action_kind
(
k
);
if
(
NULL
==
a
)
{
fprintf
(
stderr
,
"Error: non existent action: %s
\n
"
,
k
);
ret
=
-
1
;
goto
bad_val
;
}
if
(
strcmp
(
a
->
id
,
k
)
!=
0
)
{
fprintf
(
stderr
,
"Error: non existent action: %s
\n
"
,
k
);
ret
=
-
1
;
goto
bad_val
;
}
argc
-=
1
;
argv
+=
1
;
if
(
argc
<=
0
)
{
fprintf
(
stderr
,
"Error: no index specified action: %s
\n
"
,
k
);
ret
=
-
1
;
goto
bad_val
;
}
if
(
matches
(
*
argv
,
"index"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
i
,
*
argv
,
10
))
{
fprintf
(
stderr
,
"Illegal
\"
index
\"\n
"
);
ret
=
-
1
;
goto
bad_val
;
}
argc
-=
1
;
argv
+=
1
;
}
else
{
fprintf
(
stderr
,
"Error: no index specified action: %s
\n
"
,
k
);
ret
=
-
1
;
goto
bad_val
;
}
tail2
=
(
struct
rtattr
*
)
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
));
addattr_l
(
&
req
.
n
,
MAX_MSG
,
++
prio
,
NULL
,
0
);
addattr_l
(
&
req
.
n
,
MAX_MSG
,
TCA_ACT_KIND
,
k
,
strlen
(
k
)
+
1
);
addattr32
(
&
req
.
n
,
MAX_MSG
,
TCA_ACT_INDEX
,
i
);
tail2
->
rta_len
=
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
))
-
(
void
*
)
tail2
;
}
tail
->
rta_len
=
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
))
-
(
void
*
)
tail
;
if
(
rtnl_open
(
&
rth
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Cannot open rtnetlink
\n
"
);
exit
(
1
);
}
req
.
n
.
nlmsg_seq
=
rth
.
dump
=
++
rth
.
seq
;
if
(
cmd
==
RTM_GETACTION
)
ans
=
&
req
.
n
;
if
(
rtnl_talk
(
&
rth
,
&
req
.
n
,
0
,
0
,
ans
,
NULL
,
NULL
)
<
0
)
{
fprintf
(
stderr
,
"We have an error talking to the kernel
\n
"
);
rtnl_close
(
&
rth
);
exit
(
1
);
}
if
(
ans
&&
do_print_action
(
NULL
,
&
req
.
n
,
(
void
*
)
stdout
)
<
0
)
{
fprintf
(
stderr
,
"Dump terminated
\n
"
);
rtnl_close
(
&
rth
);
exit
(
1
);
}
*
argc_p
=
argc
;
*
argv_p
=
argv
;
rtnl_close
(
&
rth
);
bad_val:
return
ret
;
}
int
tc_action_modify
(
int
cmd
,
unsigned
flags
,
int
*
argc_p
,
char
***
argv_p
)
{
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
int
ret
=
0
;
struct
rtnl_handle
rth
;
struct
rtattr
*
tail
;
struct
{
struct
nlmsghdr
n
;
struct
tcamsg
t
;
char
buf
[
MAX_MSG
];
}
req
;
req
.
t
.
tca_family
=
AF_UNSPEC
;
memset
(
&
req
,
0
,
sizeof
(
req
));
req
.
n
.
nlmsg_len
=
NLMSG_LENGTH
(
sizeof
(
struct
tcamsg
));
req
.
n
.
nlmsg_flags
=
NLM_F_REQUEST
|
flags
;
req
.
n
.
nlmsg_type
=
cmd
;
tail
=
(
struct
rtattr
*
)(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
));
argc
-=
1
;
argv
+=
1
;
if
(
parse_action
(
&
argc
,
&
argv
,
TCA_ACT_TAB
,
&
req
.
n
))
{
fprintf
(
stderr
,
"Illegal
\"
action
\"\n
"
);
return
-
1
;
}
tail
->
rta_len
=
(((
void
*
)
&
req
.
n
)
+
req
.
n
.
nlmsg_len
)
-
(
void
*
)
tail
;
if
(
rtnl_open
(
&
rth
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Cannot open rtnetlink
\n
"
);
exit
(
1
);
}
if
(
rtnl_talk
(
&
rth
,
&
req
.
n
,
0
,
0
,
NULL
,
NULL
,
NULL
)
<
0
)
{
fprintf
(
stderr
,
"We have an error talking to the kernel
\n
"
);
ret
=
-
1
;
}
*
argc_p
=
argc
;
*
argv_p
=
argv
;
rtnl_close
(
&
rth
);
return
ret
;
}
int
tc_act_list_or_flush
(
int
argc
,
char
**
argv
,
int
event
)
{
int
ret
=
0
,
prio
=
0
,
msg_size
=
0
;
char
k
[
16
];
struct
rtnl_handle
rth
;
struct
rtattr
*
tail
,
*
tail2
;
struct
action_util
*
a
=
NULL
;
struct
{
struct
nlmsghdr
n
;
struct
tcamsg
t
;
char
buf
[
MAX_MSG
];
}
req
;
req
.
t
.
tca_family
=
AF_UNSPEC
;
memset
(
&
req
,
0
,
sizeof
(
req
));
req
.
n
.
nlmsg_len
=
NLMSG_LENGTH
(
sizeof
(
struct
tcamsg
));
tail
=
(
struct
rtattr
*
)(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
));
addattr_l
(
&
req
.
n
,
MAX_MSG
,
TCA_ACT_TAB
,
NULL
,
0
);
tail2
=
(
struct
rtattr
*
)
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
));
strncpy
(
k
,
*
argv
,
sizeof
(
k
)
-
1
);
#ifdef CONFIG_GACT
if
(
!
gact_ld
)
{
get_action_kind
(
"gact"
);
}
#endif
a
=
get_action_kind
(
k
);
if
(
NULL
==
a
)
{
fprintf
(
stderr
,
"bad action %s
\n
"
,
k
);
goto
bad_val
;
}
if
(
strcmp
(
a
->
id
,
k
)
!=
0
)
{
fprintf
(
stderr
,
"bad action %s
\n
"
,
k
);
goto
bad_val
;
}
strncpy
(
k
,
*
argv
,
sizeof
(
k
)
-
1
);
addattr_l
(
&
req
.
n
,
MAX_MSG
,
++
prio
,
NULL
,
0
);
addattr_l
(
&
req
.
n
,
MAX_MSG
,
TCA_ACT_KIND
,
k
,
strlen
(
k
)
+
1
);
tail2
->
rta_len
=
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
))
-
(
void
*
)
tail2
;
tail
->
rta_len
=
(((
void
*
)
&
req
.
n
)
+
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
))
-
(
void
*
)
tail
;
if
(
rtnl_open
(
&
rth
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Cannot open rtnetlink
\n
"
);
exit
(
1
);
}
msg_size
=
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
)
-
NLMSG_ALIGN
(
sizeof
(
struct
nlmsghdr
));
if
(
event
==
RTM_GETACTION
)
{
if
(
rtnl_dump_request
(
&
rth
,
event
,
(
void
*
)
&
req
.
t
,
msg_size
)
<
0
)
{
perror
(
"Cannot send dump request"
);
exit
(
1
);
}
ret
=
rtnl_dump_filter
(
&
rth
,
do_print_action
,
stdout
,
NULL
,
NULL
);
}
if
(
event
==
RTM_DELACTION
)
{
req
.
n
.
nlmsg_len
=
NLMSG_ALIGN
(
req
.
n
.
nlmsg_len
);
req
.
n
.
nlmsg_type
=
RTM_DELACTION
;
req
.
n
.
nlmsg_flags
|=
NLM_F_ROOT
;
req
.
n
.
nlmsg_flags
|=
NLM_F_REQUEST
;
if
(
rtnl_talk
(
&
rth
,
&
req
.
n
,
0
,
0
,
NULL
,
NULL
,
NULL
)
<
0
)
{
fprintf
(
stderr
,
"We have an error flushing
\n
"
);
rtnl_close
(
&
rth
);
exit
(
1
);
}
}
bad_val:
rtnl_close
(
&
rth
);
return
ret
;
}
int
do_action
(
int
argc
,
char
**
argv
)
{
int
ret
=
0
;
while
(
argc
>
0
)
{
if
(
matches
(
*
argv
,
"add"
)
==
0
)
{
ret
=
tc_action_modify
(
RTM_NEWACTION
,
NLM_F_EXCL
|
NLM_F_CREATE
,
&
argc
,
&
argv
);
}
else
if
(
matches
(
*
argv
,
"change"
)
==
0
||
matches
(
*
argv
,
"replace"
)
==
0
)
{
ret
=
tc_action_modify
(
RTM_NEWACTION
,
NLM_F_CREATE
|
NLM_F_REPLACE
,
&
argc
,
&
argv
);
}
else
if
(
matches
(
*
argv
,
"delete"
)
==
0
)
{
argc
-=
1
;
argv
+=
1
;
ret
=
tc_action_gd
(
RTM_DELACTION
,
0
,
&
argc
,
&
argv
);
}
else
if
(
matches
(
*
argv
,
"get"
)
==
0
)
{
argc
-=
1
;
argv
+=
1
;
ret
=
tc_action_gd
(
RTM_GETACTION
,
0
,
&
argc
,
&
argv
);
}
else
if
(
matches
(
*
argv
,
"list"
)
==
0
||
matches
(
*
argv
,
"show"
)
==
0
||
matches
(
*
argv
,
"lst"
)
==
0
)
{
if
(
argc
<=
2
)
{
act_usage
();
return
-
1
;
}
return
tc_act_list_or_flush
(
argc
-
2
,
argv
+
2
,
RTM_GETACTION
);
}
else
if
(
matches
(
*
argv
,
"flush"
)
==
0
)
{
if
(
argc
<=
2
)
{
act_usage
();
return
-
1
;
}
return
tc_act_list_or_flush
(
argc
-
2
,
argv
+
2
,
RTM_DELACTION
);
}
else
if
(
matches
(
*
argv
,
"help"
)
==
0
)
{
act_usage
();
return
-
1
;
}
else
{
ret
=
-
1
;
}
if
(
ret
<
0
)
{
fprintf
(
stderr
,
"Command
\"
%s
\"
is unknown, try
\"
tc action help
\"
.
\n
"
,
*
argv
);
return
-
1
;
}
}
return
0
;
}
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